aiobungie

A Pythonic async/await wrapper for interacting with the Bungie API.

Base client.

Example
import aiobungie

client = aiobungie.Client('YOUR_API_KEY')

# Search for Destiny2 users.
async def main() -> None:
    async with client.rest:
        users = await client.search_users('Crit')

        # Iterate over the users and take the first 5 results.
        for user in users.take(5):
            print(f'{user.name} ({user.code})')

            # Iterate through the users memberships.
            for membership in user.memberships:
                print(membership.type, membership.id)

client.run(main()) # or asyncio.run(main())

Single RESTClient instance.

The difference between base client and the REST clients:

  • No Hight-Level concepts.
  • All returned data are pure JSON objects from the API.
  • No object creation.
Example
import aiobungie

async def main() -> None:
    # Using `async with` context manager to close the session properly.
    async with aiobungie.RESTClient("TOKEN") as rest:
        payload = await rest.fetch_player('Fate怒', 4275)

        for membership in payload:
            print(membership['membershipId'], membership['iconPath'])

import asyncio
asyncio.run(main())

REST client pool.

A REST client pool allows you to acquire multiple RESTClient instances that shares the same connection.

Example
import aiobungie
import asyncio

pool = aiobungie.RESTPool("token")

async def func1() -> None:
    async with pool.acquire() as instance:
        tokens = await instance.fetch_oauth2_tokens('code')
        pool.metadata['tokens'] = tokens

# Other instance may access the tokens from pool since its shared.

async def func2() -> None:
    async with pool.acquire() as instance:
        tokens = pool.metadata['tokens']
        tokens = await instance.refresh_access_token(tokens.refresh_token)

async def main() -> None:
    await asyncio.gather(func1(), func2())

asyncio.run(main())

Should you use the base client or the REST client? This returns to you. For an example if you're building a website.

You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. Which gives you the freedom to deserialize it and implement your own logic in the front-end.

Or of you're building a Discord bot for an example or something simple. The base client is the way to go.

  1# MIT License
  2#
  3# Copyright (c) 2020 - Present nxtlo
  4#
  5# Permission is hereby granted, free of charge, to any person obtaining a copy
  6# of this software and associated documentation files (the "Software"), to deal
  7# in the Software without restriction, including without limitation the rights
  8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9# copies of the Software, and to permit persons to whom the Software is
 10# furnished to do so, subject to the following conditions:
 11#
 12# The above copyright notice and this permission notice shall be included in all
 13# copies or substantial portions of the Software.
 14#
 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 21# SOFTWARE.
 22
 23"""A Pythonic `async`/`await` wrapper for interacting with the Bungie API.
 24
 25Base client.
 26
 27Example
 28-------
 29```py
 30import aiobungie
 31
 32client = aiobungie.Client('YOUR_API_KEY')
 33
 34# Search for Destiny2 users.
 35async def main() -> None:
 36    async with client.rest:
 37        users = await client.search_users('Crit')
 38
 39        # Iterate over the users and take the first 5 results.
 40        for user in users.take(5):
 41            print(f'{user.name} ({user.code})')
 42
 43            # Iterate through the users memberships.
 44            for membership in user.memberships:
 45                print(membership.type, membership.id)
 46
 47client.run(main()) # or asyncio.run(main())
 48```
 49
 50Single RESTClient instance.
 51
 52The difference between base client and the REST clients:
 53
 54* No Hight-Level concepts.
 55* All returned data are pure JSON objects from the API.
 56* No object creation.
 57
 58Example
 59-------
 60```py
 61import aiobungie
 62
 63async def main() -> None:
 64    # Using `async with` context manager to close the session properly.
 65    async with aiobungie.RESTClient("TOKEN") as rest:
 66        payload = await rest.fetch_player('Fate怒', 4275)
 67
 68        for membership in payload:
 69            print(membership['membershipId'], membership['iconPath'])
 70
 71import asyncio
 72asyncio.run(main())
 73```
 74
 75REST client pool.
 76
 77A REST client pool allows you to acquire multiple `RESTClient` instances that shares the same connection.
 78
 79Example
 80-------
 81```py
 82import aiobungie
 83import asyncio
 84
 85pool = aiobungie.RESTPool("token")
 86
 87async def func1() -> None:
 88    async with pool.acquire() as instance:
 89        tokens = await instance.fetch_oauth2_tokens('code')
 90        pool.metadata['tokens'] = tokens
 91
 92# Other instance may access the tokens from pool since its shared.
 93
 94async def func2() -> None:
 95    async with pool.acquire() as instance:
 96        tokens = pool.metadata['tokens']
 97        tokens = await instance.refresh_access_token(tokens.refresh_token)
 98
 99async def main() -> None:
100    await asyncio.gather(func1(), func2())
101
102asyncio.run(main())
103```
104
105Should you use the base client or the REST client?
106This returns to you. For an example if you're building a website.
107
108You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects.
109Which gives you the freedom to deserialize it and implement your own logic in the front-end.
110
111Or of you're building a Discord bot for an example or something simple. The base client is the way to go.
112"""
113
114
115from __future__ import annotations
116
117from aiobungie import builders
118from aiobungie import crates
119from aiobungie import interfaces
120from aiobungie import traits
121from aiobungie import typedefs
122from aiobungie import url
123from aiobungie.client import Client
124from aiobungie.error import *
125from aiobungie.internal import iterators
126from aiobungie.internal.assets import Image
127from aiobungie.internal.enums import *
128from aiobungie.internal.factory import Factory
129from aiobungie.internal.iterators import *
130from aiobungie.rest import *
131from aiobungie.undefined import UNDEFINED
132from aiobungie.undefined import UndefinedOr
133from aiobungie.undefined import UndefinedType
134
135from .metadata import __about__
136from .metadata import __author__
137from .metadata import __docs__
138from .metadata import __email__
139from .metadata import __license__
140from .metadata import __url__
141from .metadata import __version__
142
143# Alias for crate for backwards compatibility.
144crate = crates
145
146# Activity enums
147from .crates.activity import Difficulty
148
149# Components enums
150from .crates.components import ComponentFields
151from .crates.components import ComponentPrivacy
152
153# Entity enums
154from .crates.entity import GatingScope
155from .crates.entity import ObjectiveUIStyle
156from .crates.entity import ValueUIStyle
157
158# Fireteam enums.
159from .crates.fireteams import FireteamActivity
160from .crates.fireteams import FireteamDate
161from .crates.fireteams import FireteamLanguage
162from .crates.fireteams import FireteamPlatform
163
164# Records enums
165from .crates.records import RecordState
166
167__all__ = [mod for mod in dir() if not mod.startswith("_")]  # type: ignore
@attrs.define(auto_exc=True)
class AiobungieError(builtins.RuntimeError):
74@attrs.define(auto_exc=True)
75class AiobungieError(RuntimeError):
76    """Base class that all other exceptions inherit from."""

Base class that all other exceptions inherit from.

AiobungieError()
2def __init__(self, ):
3    BaseException.__init__(self, )

Method generated by attrs for class AiobungieError.

Inherited Members
builtins.BaseException
with_traceback
args
@typing.final
class AmmoType(builtins.int, aiobungie.Enum):
645@typing.final
646class AmmoType(int, Enum):
647    """AN enum for Detyiny 2 ammo types."""
648
649    NONE = 0
650    PRIMARY = 1
651    SPECIAL = 2
652    HEAVY = 3

AN enum for Detyiny 2 ammo types.

NONE = <AmmoType.NONE: 0>
PRIMARY = <AmmoType.PRIMARY: 1>
SPECIAL = <AmmoType.SPECIAL: 2>
HEAVY = <AmmoType.HEAVY: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class BadRequest(aiobungie.HTTPError):
164@attrs.define(auto_exc=True)
165class BadRequest(HTTPError):
166    """An exception raised when requesting a resource with the provided data is wrong."""
167
168    url: typing.Optional[typedefs.StrOrURL]
169    """The URL/endpoint caused this error."""
170
171    body: typing.Any
172    """The response body."""
173
174    headers: multidict.CIMultiDictProxy[str]
175    """The response headers."""
176
177    http_status: http.HTTPStatus = attrs.field(
178        default=http.HTTPStatus.BAD_REQUEST, init=False
179    )

An exception raised when requesting a resource with the provided data is wrong.

BadRequest( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str])
2def __init__(self, message, url, body, headers):
3    self.message = message
4    self.url = url
5    self.body = body
6    self.headers = headers
7    self.http_status = attr_dict['http_status'].default
8    BaseException.__init__(self, self.message,self.url,self.body,self.headers)

Method generated by attrs for class BadRequest.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

http_status: http.HTTPStatus

The response status.

Inherited Members
HTTPError
message
builtins.BaseException
with_traceback
args
@typing.final
class ClanMemberType(builtins.int, aiobungie.Enum):
700@typing.final
701class ClanMemberType(int, Enum):
702    """An enum for bungie clan member types."""
703
704    NONE = 0
705    BEGINNER = 1
706    MEMBER = 2
707    ADMIN = 3
708    ACTING_FOUNDER = 4
709    FOUNDER = 5

An enum for bungie clan member types.

NONE = <ClanMemberType.NONE: 0>
BEGINNER = <ClanMemberType.BEGINNER: 1>
MEMBER = <ClanMemberType.MEMBER: 2>
ADMIN = <ClanMemberType.ADMIN: 3>
ACTING_FOUNDER = <ClanMemberType.ACTING_FOUNDER: 4>
FOUNDER = <ClanMemberType.FOUNDER: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Class(builtins.int, aiobungie.Enum):
476@typing.final
477class Class(int, Enum):
478    """An Enum for Destiny character classes."""
479
480    TITAN = 0
481    HUNTER = 1
482    WARLOCK = 2
483    UNKNOWN = 3

An Enum for Destiny character classes.

TITAN = <Class.TITAN: 0>
HUNTER = <Class.HUNTER: 1>
WARLOCK = <Class.WARLOCK: 2>
UNKNOWN = <Class.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Client(aiobungie.traits.ClientApp):
  60class Client(traits.ClientApp):
  61    """Standard Bungie API client application.
  62
  63    This client deserialize the REST JSON responses using `aiobungie.internal.factory.Factory`
  64    and returns `aiobungie.crates` Python object implementations of the responses.
  65
  66    A `aiobungie.RESTClient` REST client can also be used alone for low-level concepts.
  67
  68    Example
  69    -------
  70    ```py
  71    import aiobungie
  72
  73    client = aiobungie.Client('...')
  74
  75    async def main():
  76        async with client.rest:
  77            user = await client.fetch_current_user_memberships('...')
  78            print(user)
  79    ```
  80
  81    Parameters
  82    -----------
  83    token: `str`
  84        Your Bungie's API key or Token from the developer's portal.
  85
  86    Other Parameters
  87    ----------------
  88    max_retries : `int`
  89        The max retries number to retry if the request hit a `5xx` status code.
  90    client_secret : `str | None`
  91        An optional application client secret,
  92        This is only needed if you're fetching OAuth2 tokens with this client.
  93    client_id : `int | None`
  94        An optional application client id,
  95        This is only needed if you're fetching OAuth2 tokens with this client.
  96    """
  97
  98    __slots__ = ("_rest", "_factory")
  99
 100    def __init__(
 101        self,
 102        token: str,
 103        /,
 104        *,
 105        client_secret: typing.Optional[str] = None,
 106        client_id: typing.Optional[int] = None,
 107        max_retries: int = 4,
 108    ) -> None:
 109        self._rest = rest_.RESTClient(
 110            token,
 111            client_secret=client_secret,
 112            client_id=client_id,
 113            max_retries=max_retries,
 114        )
 115
 116        self._factory = factory_.Factory(self)
 117
 118    @property
 119    def factory(self) -> factory_.Factory:
 120        return self._factory
 121
 122    @property
 123    def rest(self) -> interfaces.RESTInterface:
 124        return self._rest
 125
 126    @property
 127    def request(self) -> Client:
 128        return self
 129
 130    @property
 131    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 132        return self._rest.metadata
 133
 134    def run(
 135        self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False
 136    ) -> None:
 137        loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop()
 138        try:
 139            if not loop.is_running():
 140                loop.set_debug(debug)
 141                loop.run_until_complete(future)
 142
 143        except Exception as exc:
 144            raise RuntimeError(f"Failed to run {future.__qualname__}") from exc
 145
 146        except KeyboardInterrupt:
 147            _LOG.warn("Unexpected Keyboard interrupt. Exiting.")
 148            return
 149
 150    # * User methods.
 151
 152    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
 153        """Fetch and return a user object of the bungie net user associated with account.
 154
 155        .. warning::
 156            This method requires OAuth2 scope and a Bearer access token.
 157
 158        Parameters
 159        ----------
 160        access_token : `str`
 161            A valid Bearer access token for the authorization.
 162
 163        Returns
 164        -------
 165        `aiobungie.crates.user.User`
 166            A user object includes the Destiny memberships and Bungie.net user.
 167        """
 168        resp = await self.rest.fetch_current_user_memberships(access_token)
 169
 170        return self.factory.deserialize_user(resp)
 171
 172    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
 173        """Fetch a Bungie user by their BungieNet id.
 174
 175        .. note::
 176            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
 177            for other memberships.
 178
 179        Parameters
 180        ----------
 181        id: `int`
 182            The user id.
 183
 184        Returns
 185        -------
 186        `aiobungie.crates.user.BungieUser`
 187            A Bungie user.
 188
 189        Raises
 190        ------
 191        `aiobungie.error.NotFound`
 192            The user was not found.
 193        """
 194        payload = await self.rest.fetch_bungie_user(id)
 195
 196        return self.factory.deserialize_bungie_user(payload)
 197
 198    async def search_users(
 199        self, name: str, /
 200    ) -> iterators.Iterator[user.SearchableDestinyUser]:
 201        """Search for players and return all players that matches the same name.
 202
 203        Parameters
 204        ----------
 205        name : `buildins.str`
 206            The user name.
 207
 208        Returns
 209        -------
 210        `aiobungie.iterators.Iterator[aiobungie.crates.DestinyMembership]`
 211            A sequence of destiny memberships.
 212        """
 213        payload = await self.rest.search_users(name)
 214
 215        return iterators.Iterator(
 216            [
 217                self.factory.deserialize_searched_user(user)
 218                for user in payload["searchResults"]
 219            ]
 220        )
 221
 222    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
 223        """Fetch all available user themes.
 224
 225        Returns
 226        -------
 227        `collections.Sequence[aiobungie.crates.user.UserThemes]`
 228            A sequence of user themes.
 229        """
 230        data = await self.rest.fetch_user_themes()
 231
 232        return self.factory.deserialize_user_themes(data)
 233
 234    async def fetch_hard_types(
 235        self,
 236        credential: int,
 237        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
 238        /,
 239    ) -> user.HardLinkedMembership:
 240        """Gets any hard linked membership given a credential.
 241        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
 242        Cross Save aware.
 243
 244        Parameters
 245        ----------
 246        credential: `int`
 247            A valid SteamID64
 248        type: `aiobungie.CredentialType`
 249            The credential type. This must not be changed
 250            Since its only credential that works "currently"
 251
 252        Returns
 253        -------
 254        `aiobungie.crates.user.HardLinkedMembership`
 255            Information about the hard linked data.
 256        """
 257
 258        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
 259
 260        return user.HardLinkedMembership(
 261            id=int(payload["membershipId"]),
 262            type=enums.MembershipType(payload["membershipType"]),
 263            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
 264        )
 265
 266    async def fetch_membership_from_id(
 267        self,
 268        id: int,
 269        /,
 270        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 271    ) -> user.User:
 272        """Fetch Bungie user's memberships from their id.
 273
 274        Notes
 275        -----
 276        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
 277        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
 278        see `aiobungie.crates.user.DestinyMembership` for more details.
 279        * If you only want the bungie user. Consider using `Client.fetch_user` method.
 280
 281        Parameters
 282        ----------
 283        id : `int`
 284            The user's id.
 285        type : `aiobungie.MembershipType`
 286            The user's membership type.
 287
 288        Returns
 289        -------
 290        `aiobungie.crates.User`
 291            A Bungie user with their membership types.
 292
 293        Raises
 294        ------
 295        aiobungie.NotFound
 296            The requested user was not found.
 297        """
 298        payload = await self.rest.fetch_membership_from_id(id, type)
 299
 300        return self.factory.deserialize_user(payload)
 301
 302    async def fetch_user_credentials(
 303        self, access_token: str, membership_id: int, /
 304    ) -> collections.Sequence[user.UserCredentials]:
 305        """Fetch an array of credential types attached to the requested account.
 306
 307        .. note::
 308            This method require OAuth2 Bearer access token.
 309
 310        Parameters
 311        ----------
 312        access_token : `str`
 313            The bearer access token associated with the bungie account.
 314        membership_id : `int`
 315            The id of the membership to return.
 316
 317        Returns
 318        -------
 319        `collections.Sequence[aiobungie.crates.UserCredentials]`
 320            A sequence of the attached user credentials.
 321
 322        Raises
 323        ------
 324        `aiobungie.Unauthorized`
 325            The access token was wrong or no access token passed.
 326        """
 327        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
 328
 329        return self.factory.deserialize_user_credentials(resp)
 330
 331    # * Destiny 2.
 332
 333    async def fetch_profile(
 334        self,
 335        member_id: int,
 336        type: typedefs.IntAnd[enums.MembershipType],
 337        components: list[enums.ComponentType],
 338        auth: typing.Optional[str] = None,
 339    ) -> components.Component:
 340        """
 341        Fetch a bungie profile passing components to the request.
 342
 343        Parameters
 344        ----------
 345        member_id: `int`
 346            The member's id.
 347        type: `aiobungie.MembershipType`
 348            A valid membership type.
 349        components : `list[aiobungie.ComponentType]`
 350            List of profile components to collect and return.
 351
 352        Other Parameters
 353        ----------------
 354        auth : `typing.Optional[str]`
 355            A Bearer access_token to make the request with.
 356            This is optional and limited to components that only requires an Authorization token.
 357
 358        Returns
 359        --------
 360        `aiobungie.crates.Component`
 361            A Destiny 2 player profile with its components.
 362            Only passed components will be available if they exists. Otherwise they will be `None`
 363
 364        Raises
 365        ------
 366        `aiobungie.MembershipTypeError`
 367            The provided membership type was invalid.
 368        """
 369        data = await self.rest.fetch_profile(member_id, type, components, auth)
 370        return self.factory.deserialize_components(data)
 371
 372    async def fetch_linked_profiles(
 373        self,
 374        member_id: int,
 375        member_type: typedefs.IntAnd[enums.MembershipType],
 376        /,
 377        *,
 378        all: bool = False,
 379    ) -> profile.LinkedProfile:
 380        """Returns a summary information about all profiles linked to the requested member.
 381
 382        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
 383
 384        .. note::
 385            It will only return linked accounts whose linkages you are allowed to view.
 386
 387        Parameters
 388        ----------
 389        member_id : `int`
 390            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
 391        member_type : `aiobungie.MembershipType`
 392            The type for the membership whose linked Destiny account you want to return.
 393
 394        Other Parameters
 395        ----------------
 396        all : `bool`
 397            If provided and set to `True`, All memberships regardless
 398            of whether they're obscured by overrides will be returned,
 399
 400            If provided and set to `False`, Only available memberships will be returned.
 401            The default for this is `False`.
 402
 403        Returns
 404        -------
 405        `aiobungie.crates.profile.LinkedProfile`
 406            A linked profile object.
 407        """
 408        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
 409
 410        return self.factory.deserialize_linked_profiles(resp)
 411
 412    async def fetch_player(
 413        self,
 414        name: str,
 415        code: int,
 416        /,
 417        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
 418    ) -> collections.Sequence[user.DestinyMembership]:
 419        """Fetch a Destiny 2 player's memberships.
 420
 421        Parameters
 422        -----------
 423        name: `str`
 424            The unique Bungie player name.
 425        code : `int`
 426            The unique Bungie display name code.
 427        type: `aiobungie.internal.enums.MembershipType`
 428            The player's membership type, e,g. XBOX, STEAM, PSN
 429
 430        Returns
 431        --------
 432        `collections.Sequence[aiobungie.crates.DestinyMembership]`
 433            A sequence of the found Destiny 2 player memberships.
 434            An empty sequence will be returned if no one found.
 435
 436        Raises
 437        ------
 438        `aiobungie.MembershipTypeError`
 439            The provided membership type was invalid.
 440        """
 441        resp = await self.rest.fetch_player(name, code, type)
 442
 443        return self.factory.deserialize_destiny_memberships(resp)
 444
 445    async def fetch_character(
 446        self,
 447        member_id: int,
 448        membership_type: typedefs.IntAnd[enums.MembershipType],
 449        character_id: int,
 450        components: list[enums.ComponentType],
 451        auth: typing.Optional[str] = None,
 452    ) -> components.CharacterComponent:
 453        """Fetch a Destiny 2 character.
 454
 455        Parameters
 456        ----------
 457        member_id: `int`
 458            A valid bungie member id.
 459        character_id: `int`
 460            The Destiny character id to retrieve.
 461        membership_type: `aiobungie.internal.enums.MembershipType`
 462            The member's membership type.
 463        components: `list[aiobungie.ComponentType]`
 464            Multiple arguments of character components to collect and return.
 465
 466        Other Parameters
 467        ----------------
 468        auth : `typing.Optional[str]`
 469            A Bearer access_token to make the request with.
 470            This is optional and limited to components that only requires an Authorization token.
 471
 472        Returns
 473        -------
 474        `aiobungie.crates.CharacterComponent`
 475            A Bungie character component.
 476
 477        `aiobungie.MembershipTypeError`
 478            The provided membership type was invalid.
 479        """
 480        resp = await self.rest.fetch_character(
 481            member_id, membership_type, character_id, components, auth
 482        )
 483
 484        return self.factory.deserialize_character_component(resp)
 485
 486    async def fetch_unique_weapon_history(
 487        self,
 488        membership_id: int,
 489        character_id: int,
 490        membership_type: typedefs.IntAnd[enums.MembershipType],
 491    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
 492        """Fetch details about unique weapon usage for a character. Includes all exotics.
 493
 494        Parameters
 495        ----------
 496        membership_id : `int`
 497            The Destiny user membership id.
 498        character_id : `int`
 499            The character id to retrieve.
 500        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 501            The Destiny user's membership type.
 502
 503        Returns
 504        -------
 505        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
 506            A sequence of the weapon's extended values.
 507        """
 508        resp = await self._rest.fetch_unique_weapon_history(
 509            membership_id, character_id, membership_type
 510        )
 511
 512        return [
 513            self._factory.deserialize_extended_weapon_values(weapon)
 514            for weapon in resp["weapons"]
 515        ]
 516
 517    # * Destiny 2 Activities.
 518
 519    async def fetch_activities(
 520        self,
 521        member_id: int,
 522        character_id: int,
 523        mode: typedefs.IntAnd[enums.GameMode],
 524        *,
 525        membership_type: typedefs.IntAnd[
 526            enums.MembershipType
 527        ] = enums.MembershipType.ALL,
 528        page: int = 0,
 529        limit: int = 250,
 530    ) -> iterators.Iterator[activity.Activity]:
 531        """Fetch a Destiny 2 activity for the specified character id.
 532
 533        Parameters
 534        ----------
 535        member_id: `int`
 536            The user id that starts with `4611`.
 537        character_id: `int`
 538            The id of the character to retrieve the activities for.
 539        mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]`
 540            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
 541
 542        Other Parameters
 543        ----------------
 544        membership_type: `aiobungie.internal.enums.MembershipType`
 545            The Member ship type, if nothing was passed than it will return all.
 546        page: int
 547            The page number. Default is `0`
 548        limit: int
 549            Limit the returned result. Default is `250`.
 550
 551        Returns
 552        -------
 553        `aiobungie.iterators.Iterator[aiobungie.crates.Activity]`
 554            An iterator of the player's activities.
 555
 556        Raises
 557        ------
 558        `aiobungie.MembershipTypeError`
 559            The provided membership type was invalid.
 560        """
 561        resp = await self.rest.fetch_activities(
 562            member_id,
 563            character_id,
 564            mode,
 565            membership_type=membership_type,
 566            page=page,
 567            limit=limit,
 568        )
 569
 570        return self.factory.deserialize_activities(resp)
 571
 572    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
 573        """Fetch a post activity details.
 574
 575        Parameters
 576        ----------
 577        instance_id: `int`
 578            The activity instance id.
 579
 580        Returns
 581        -------
 582        `aiobungie.crates.PostActivity`
 583           A post activity object.
 584        """
 585        resp = await self.rest.fetch_post_activity(instance_id)
 586
 587        return self.factory.deserialize_post_activity(resp)
 588
 589    async def fetch_aggregated_activity_stats(
 590        self,
 591        character_id: int,
 592        membership_id: int,
 593        membership_type: typedefs.IntAnd[enums.MembershipType],
 594    ) -> iterators.Iterator[activity.AggregatedActivity]:
 595        """Fetch aggregated activity stats for a character.
 596
 597        Parameters
 598        ----------
 599        character_id: `int`
 600            The id of the character to retrieve the activities for.
 601        membership_id: `int`
 602            The id of the user that started with `4611`.
 603        membership_type: `aiobungie.internal.enums.MembershipType`
 604            The Member ship type.
 605
 606        Returns
 607        -------
 608        `aiobungie.iterators.Iterator[aiobungie.crates.AggregatedActivity]`
 609            An iterator of the player's activities.
 610
 611        Raises
 612        ------
 613        `aiobungie.MembershipTypeError`
 614            The provided membership type was invalid.
 615        """
 616        resp = await self.rest.fetch_aggregated_activity_stats(
 617            character_id, membership_id, membership_type
 618        )
 619
 620        return self.factory.deserialize_aggregated_activities(resp)
 621
 622    # * Destiny 2 Clans or GroupsV2.
 623
 624    async def fetch_clan_from_id(
 625        self,
 626        id: int,
 627        /,
 628        access_token: typing.Optional[str] = None,
 629    ) -> clans.Clan:
 630        """Fetch a Bungie Clan by its id.
 631
 632        Parameters
 633        -----------
 634        id: `int`
 635            The clan id.
 636
 637        Returns
 638        --------
 639        `aiobungie.crates.Clan`
 640            An Bungie clan.
 641
 642        Raises
 643        ------
 644        `aiobungie.NotFound`
 645            The clan was not found.
 646        """
 647        resp = await self.rest.fetch_clan_from_id(id, access_token)
 648
 649        return self.factory.deserialize_clan(resp)
 650
 651    async def fetch_clan(
 652        self,
 653        name: str,
 654        /,
 655        access_token: typing.Optional[str] = None,
 656        *,
 657        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 658    ) -> clans.Clan:
 659        """Fetch a Clan by its name.
 660        This method will return the first clan found with given name.
 661
 662        Parameters
 663        ----------
 664        name: `str`
 665            The clan name
 666
 667        Other Parameters
 668        ----------------
 669        access_token : `typing.Optional[str]`
 670            An optional access token to make the request with.
 671
 672            If the token was bound to a member of the clan,
 673            This field `aiobungie.crates.Clan.current_user_membership` will be available
 674            and will return the membership of the user who made this request.
 675        type : `aiobungie.GroupType`
 676            The group type, Default is aiobungie.GroupType.CLAN.
 677
 678        Returns
 679        -------
 680        `aiobungie.crates.Clan`
 681            A Bungie clan.
 682
 683        Raises
 684        ------
 685        `aiobungie.NotFound`
 686            The clan was not found.
 687        """
 688        resp = await self.rest.fetch_clan(name, access_token, type=type)
 689
 690        return self.factory.deserialize_clan(resp)
 691
 692    async def fetch_clan_conversations(
 693        self, clan_id: int, /
 694    ) -> collections.Sequence[clans.ClanConversation]:
 695        """Fetch the conversations/chat channels of the given clan id.
 696
 697        Parameters
 698        ----------
 699        clan_id : `int`
 700            The clan id.
 701
 702        Returns
 703        `collections.Sequence[aiobungie.crates.ClanConversation]`
 704            A sequence of the clan chat channels.
 705        """
 706        resp = await self.rest.fetch_clan_conversations(clan_id)
 707
 708        return self.factory.deserialize_clan_conversations(resp)
 709
 710    async def fetch_clan_admins(
 711        self, clan_id: int, /
 712    ) -> iterators.Iterator[clans.ClanMember]:
 713        """Fetch the clan founder and admins.
 714
 715        Parameters
 716        ----------
 717        clan_id : `int`
 718            The clan id.
 719
 720        Returns
 721        -------
 722        `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]`
 723            An iterator over the found clan admins and founder.
 724
 725        Raises
 726        ------
 727        `aiobungie.NotFound`
 728            The requested clan was not found.
 729        """
 730        resp = await self.rest.fetch_clan_admins(clan_id)
 731
 732        return self.factory.deserialize_clan_members(resp)
 733
 734    async def fetch_groups_for_member(
 735        self,
 736        member_id: int,
 737        member_type: typedefs.IntAnd[enums.MembershipType],
 738        /,
 739        *,
 740        filter: int = 0,
 741        group_type: enums.GroupType = enums.GroupType.CLAN,
 742    ) -> collections.Sequence[clans.GroupMember]:
 743        """Fetch information about the groups that a given member has joined.
 744
 745        Parameters
 746        ----------
 747        member_id : `int`
 748            The member's id
 749        member_type : `aiobungie.MembershipType`
 750            The member's membership type.
 751
 752        Other Parameters
 753        ----------------
 754        filter : `int`
 755            Filter apply to list of joined groups. This Default to `0`
 756        group_type : `aiobungie.GroupType`
 757            The group's type.
 758            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 759
 760        Returns
 761        -------
 762        `collections.Sequence[aiobungie.crates.GroupMember]`
 763            A sequence of joined groups for the fetched member.
 764        """
 765        resp = await self.rest.fetch_groups_for_member(
 766            member_id, member_type, filter=filter, group_type=group_type
 767        )
 768
 769        return [
 770            self.factory.deserialize_group_member(group) for group in resp["results"]
 771        ]
 772
 773    async def fetch_potential_groups_for_member(
 774        self,
 775        member_id: int,
 776        member_type: typedefs.IntAnd[enums.MembershipType],
 777        /,
 778        *,
 779        filter: int = 0,
 780        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 781    ) -> collections.Sequence[clans.GroupMember]:
 782        """Fetch the potential groups for a clan member.
 783
 784        Parameters
 785        ----------
 786        member_id : `int`
 787            The member's id
 788        member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 789            The member's membership type.
 790
 791        Other Parameters
 792        ----------------
 793        filter : `int`
 794            Filter apply to list of joined groups. This Default to `0`
 795        group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]`
 796            The group's type.
 797            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 798
 799        Returns
 800        -------
 801        `collections.Sequence[aiobungie.crates.GroupMember]`
 802            A sequence of joined potential groups for the fetched member.
 803        """
 804        resp = await self.rest.fetch_potential_groups_for_member(
 805            member_id, member_type, filter=filter, group_type=group_type
 806        )
 807
 808        return [
 809            self.factory.deserialize_group_member(group) for group in resp["results"]
 810        ]
 811
 812    async def fetch_clan_members(
 813        self,
 814        clan_id: int,
 815        /,
 816        *,
 817        name: typing.Optional[str] = None,
 818        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 819    ) -> iterators.Iterator[clans.ClanMember]:
 820        """Fetch Bungie clan members.
 821
 822        Parameters
 823        ----------
 824        clan_id : `int`
 825            The clans id
 826
 827        Other Parameters
 828        ----------------
 829        name : `typing.Optional[str]`
 830            If provided, Only players matching this name will be returned.
 831        type : `aiobungie.MembershipType`
 832            An optional clan member's membership type.
 833            This parameter is used to filter the returned results
 834            by the provided membership, For an example XBox memberships only,
 835            Otherwise will return all memberships.
 836
 837        Returns
 838        -------
 839        `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]`
 840            An iterator over the bungie clan members.
 841
 842        Raises
 843        ------
 844        `aiobungie.NotFound`
 845            The clan was not found.
 846        """
 847        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
 848
 849        return self.factory.deserialize_clan_members(resp)
 850
 851    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
 852        """Fetch the clan banners.
 853
 854        Returns
 855        -------
 856        `collections.Sequence[aiobungie.crates.ClanBanner]`
 857            A sequence of the clan banners.
 858        """
 859        resp = await self.rest.fetch_clan_banners()
 860
 861        return self.factory.deserialize_clan_banners(resp)
 862
 863    # This method is required to be here since it deserialize the clan.
 864    async def kick_clan_member(
 865        self,
 866        access_token: str,
 867        /,
 868        group_id: int,
 869        membership_id: int,
 870        membership_type: typedefs.IntAnd[enums.MembershipType],
 871    ) -> clans.Clan:
 872        """Kick a member from the clan.
 873
 874        .. note::
 875            This request requires OAuth2: oauth2: `AdminGroups` scope.
 876
 877        Parameters
 878        ----------
 879        access_token : `str`
 880            The bearer access token associated with the bungie account.
 881        group_id: `int`
 882            The group id.
 883        membership_id : `int`
 884            The member id to kick.
 885        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 886            The member's membership type.
 887
 888        Returns
 889        -------
 890        `aiobungie.crates.clan.Clan`
 891            The clan that the member was kicked from.
 892        """
 893        resp = await self.rest.kick_clan_member(
 894            access_token,
 895            group_id=group_id,
 896            membership_id=membership_id,
 897            membership_type=membership_type,
 898        )
 899
 900        return self.factory.deserialize_clan(resp)
 901
 902    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
 903        """Fetch a Bungie clan's weekly reward state.
 904
 905        Parameters
 906        ----------
 907        clan_id : `int`
 908            The clan's id.
 909
 910        Returns
 911        -------
 912        `aiobungie.crates.Milestone`
 913            A runtime status of the clan's milestone data.
 914        """
 915
 916        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
 917
 918        return self.factory.deserialize_milestone(resp)
 919
 920    # * Destiny 2 Entities aka Definitions.
 921
 922    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
 923        """Fetch a static inventory item entity given a its hash.
 924
 925        Parameters
 926        ----------
 927        hash: `int`
 928            Inventory item's hash.
 929
 930        Returns
 931        -------
 932        `aiobungie.crates.InventoryEntity`
 933            A bungie inventory item.
 934        """
 935        resp = await self.rest.fetch_inventory_item(hash)
 936
 937        return self.factory.deserialize_inventory_entity(resp)
 938
 939    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
 940        """Fetch a Destiny objective entity given a its hash.
 941
 942        Parameters
 943        ----------
 944        hash: `int`
 945            objective's hash.
 946
 947        Returns
 948        -------
 949        `aiobungie.crates.ObjectiveEntity`
 950            An objective entity item.
 951        """
 952        resp = await self.rest.fetch_objective_entity(hash)
 953
 954        return self.factory.deserialize_objective_entity(resp)
 955
 956    async def search_entities(
 957        self, name: str, entity_type: str, *, page: int = 0
 958    ) -> iterators.Iterator[entity.SearchableEntity]:
 959        """Search for Destiny2 entities given a name and its type.
 960
 961        Parameters
 962        ----------
 963        name : `str`
 964            The name of the entity, i.e., Thunderlord, One thousand voices.
 965        entity_type : `str`
 966            The type of the entity, AKA Definition,
 967            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
 968
 969        Other Parameters
 970        ----------------
 971        page : `int`
 972            An optional page to return. Default to 0.
 973
 974        Returns
 975        -------
 976        `aiobungie.iterators.Iterator[aiobungie.crates.SearchableEntity]`
 977            An iterator over the found results matching the provided name.
 978        """
 979        resp = await self.rest.search_entities(name, entity_type, page=page)
 980
 981        return self.factory.deserialize_inventory_results(resp)
 982
 983    # Fireteams
 984
 985    async def fetch_fireteams(
 986        self,
 987        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
 988        *,
 989        platform: typedefs.IntAnd[
 990            fireteams.FireteamPlatform
 991        ] = fireteams.FireteamPlatform.ANY,
 992        language: typing.Union[
 993            fireteams.FireteamLanguage, str
 994        ] = fireteams.FireteamLanguage.ALL,
 995        date_range: int = 0,
 996        page: int = 0,
 997        slots_filter: int = 0,
 998    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
 999        """Fetch public Bungie fireteams with open slots.
1000
1001        Parameters
1002        ----------
1003        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1004            The fireteam activity type.
1005
1006        Other Parameters
1007        ----------------
1008        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1009            If this is provided. Then the results will be filtered with the given platform.
1010            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1011        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1012            A locale language to filter the used language in that fireteam.
1013            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1014        date_range : `int`
1015            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1016        page : `int`
1017            The page number. By default its `0` which returns all available activities.
1018        slots_filter : `int`
1019            Filter the returned fireteams based on available slots. Default is `0`
1020
1021        Returns
1022        -------
1023        `typing.Optional[collections.Sequence[fireteams.Fireteam]]`
1024            A sequence of `aiobungie.crates.Fireteam` or `None`.
1025        """
1026
1027        resp = await self.rest.fetch_fireteams(
1028            activity_type,
1029            platform=platform,
1030            language=language,
1031            date_range=date_range,
1032            page=page,
1033            slots_filter=slots_filter,
1034        )
1035
1036        return self.factory.deserialize_fireteams(resp)
1037
1038    async def fetch_avaliable_clan_fireteams(
1039        self,
1040        access_token: str,
1041        group_id: int,
1042        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1043        *,
1044        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1045        language: typing.Union[fireteams.FireteamLanguage, str],
1046        date_range: int = 0,
1047        page: int = 0,
1048        public_only: bool = False,
1049        slots_filter: int = 0,
1050    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1051        """Fetch a clan's fireteams with open slots.
1052
1053        .. note::
1054            This method requires OAuth2: ReadGroups scope.
1055
1056        Parameters
1057        ----------
1058        access_token : `str`
1059            The bearer access token associated with the bungie account.
1060        group_id : `int`
1061            The group/clan id of the fireteam.
1062        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1063            The fireteam activity type.
1064
1065        Other Parameters
1066        ----------------
1067        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1068            If this is provided. Then the results will be filtered with the given platform.
1069            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1070        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1071            A locale language to filter the used language in that fireteam.
1072            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1073        date_range : `int`
1074            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1075        page : `int`
1076            The page number. By default its `0` which returns all available activities.
1077        public_only: `bool`
1078            If set to True, Then only public fireteams will be returned.
1079        slots_filter : `int`
1080            Filter the returned fireteams based on available slots. Default is `0`
1081
1082        Returns
1083        -------
1084        `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]`
1085            A sequence of  fireteams found in the clan.
1086            `None` will be returned if nothing was found.
1087        """
1088        resp = await self.rest.fetch_avaliable_clan_fireteams(
1089            access_token,
1090            group_id,
1091            activity_type,
1092            platform=platform,
1093            language=language,
1094            date_range=date_range,
1095            page=page,
1096            public_only=public_only,
1097            slots_filter=slots_filter,
1098        )
1099
1100        return self.factory.deserialize_fireteams(resp)
1101
1102    async def fetch_clan_fireteam(
1103        self, access_token: str, fireteam_id: int, group_id: int
1104    ) -> fireteams.AvailableFireteam:
1105        """Fetch a specific clan fireteam.
1106
1107        .. note::
1108            This method requires OAuth2: ReadGroups scope.
1109
1110        Parameters
1111        ----------
1112        access_token : `str`
1113            The bearer access token associated with the bungie account.
1114        group_id : `int`
1115            The group/clan id to fetch the fireteam from.
1116        fireteam_id : `int`
1117            The fireteam id to fetch.
1118
1119        Returns
1120        -------
1121        `typing.Optional[aiobungie.crates.AvailableFireteam]`
1122            A sequence of available fireteams objects if exists. else `None` will be returned.
1123        """
1124        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1125
1126        return self.factory.deserialize_available_fireteams(
1127            resp, no_results=True
1128        )  # type: ignore[return-value]
1129
1130    async def fetch_my_clan_fireteams(
1131        self,
1132        access_token: str,
1133        group_id: int,
1134        *,
1135        include_closed: bool = True,
1136        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1137        language: typing.Union[fireteams.FireteamLanguage, str],
1138        filtered: bool = True,
1139        page: int = 0,
1140    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1141        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1142
1143        .. note::
1144            This method requires OAuth2: ReadGroups scope.
1145
1146        Parameters
1147        ----------
1148        access_token : str
1149            The bearer access token associated with the bungie account.
1150        group_id : int
1151            The group/clan id to fetch.
1152
1153        Other Parameters
1154        ----------------
1155        include_closed : bool
1156            If provided and set to True, It will also return closed fireteams.
1157            If provided and set to False, It will only return public fireteams. Default is True.
1158        platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]
1159            If this is provided. Then the results will be filtered with the given platform.
1160            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1161        language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]
1162            A locale language to filter the used language in that fireteam.
1163            Defaults to aiobungie.crates.FireteamLanguage.ALL
1164        filtered : bool
1165            If set to True, it will filter by clan. Otherwise not. Default is True.
1166        page : int
1167            The page number. By default its 0 which returns all available activities.
1168
1169        Returns
1170        -------
1171        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1172            A sequence of available fireteams objects if exists. else `None` will be returned.
1173        """
1174        resp = await self.rest.fetch_my_clan_fireteams(
1175            access_token,
1176            group_id,
1177            include_closed=include_closed,
1178            platform=platform,
1179            language=language,
1180            filtered=filtered,
1181            page=page,
1182        )
1183
1184        return self.factory.deserialize_available_fireteams(resp)  # type: ignore[return-value]
1185
1186    # Friends and social.
1187
1188    async def fetch_friends(
1189        self, access_token: str, /
1190    ) -> collections.Sequence[friends.Friend]:
1191        """Fetch bungie friend list.
1192
1193        .. note::
1194            This requests OAuth2: ReadUserData scope.
1195
1196        Parameters
1197        -----------
1198        access_token : `str`
1199            The bearer access token associated with the bungie account.
1200
1201        Returns
1202        -------
1203        `collections.Sequence[aiobungie.crates.Friend]`
1204            A sequence of the friends associated with that access token.
1205        """
1206
1207        resp = await self.rest.fetch_friends(access_token)
1208
1209        return self.factory.deserialize_friends(resp)
1210
1211    async def fetch_friend_requests(
1212        self, access_token: str, /
1213    ) -> friends.FriendRequestView:
1214        """Fetch pending bungie friend requests queue.
1215
1216        .. note::
1217            This requests OAuth2: ReadUserData scope.
1218
1219        Parameters
1220        -----------
1221        access_token : `str`
1222            The bearer access token associated with the bungie account.
1223
1224        Returns
1225        -------
1226        `aiobungie.crates.FriendRequestView`
1227            A friend requests view of that associated access token.
1228        """
1229
1230        resp = await self.rest.fetch_friend_requests(access_token)
1231
1232        return self.factory.deserialize_friend_requests(resp)
1233
1234    # Applications and Developer portal.
1235
1236    async def fetch_application(self, appid: int, /) -> application.Application:
1237        """Fetch a Bungie application.
1238
1239        Parameters
1240        -----------
1241        appid: `int`
1242            The application id.
1243
1244        Returns
1245        --------
1246        `aiobungie.crates.Application`
1247            A Bungie application.
1248        """
1249        resp = await self.rest.fetch_application(appid)
1250
1251        return self.factory.deserialize_app(resp)
1252
1253    # Milestones
1254
1255    async def fetch_public_milestone_content(
1256        self, milestone_hash: int, /
1257    ) -> milestones.MilestoneContent:
1258        """Fetch the milestone content given its hash.
1259
1260        Parameters
1261        ----------
1262        milestone_hash : `int`
1263            The milestone hash.
1264
1265        Returns
1266        -------
1267        `aiobungie.crates.milestones.MilestoneContent`
1268            A milestone content object.
1269        """
1270        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1271
1272        return self.factory.deserialize_public_milestone_content(resp)

Standard Bungie API client application.

This client deserialize the REST JSON responses using Factory and returns aiobungie.crates Python object implementations of the responses.

A aiobungie.RESTClient REST client can also be used alone for low-level concepts.

Example
import aiobungie

client = aiobungie.Client('...')

async def main():
    async with client.rest:
        user = await client.fetch_current_user_memberships('...')
        print(user)
Parameters
  • token (str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
Client( token: str, /, *, client_secret: Optional[str] = None, client_id: Optional[int] = None, max_retries: int = 4)
100    def __init__(
101        self,
102        token: str,
103        /,
104        *,
105        client_secret: typing.Optional[str] = None,
106        client_id: typing.Optional[int] = None,
107        max_retries: int = 4,
108    ) -> None:
109        self._rest = rest_.RESTClient(
110            token,
111            client_secret=client_secret,
112            client_id=client_id,
113            max_retries=max_retries,
114        )
115
116        self._factory = factory_.Factory(self)
factory: Factory

Returns the marshalling factory for the client.

rest: aiobungie.interfaces.rest.RESTInterface

Returns the REST client for the this client.

request: Client

A readonly ClientApp instance used for external requests.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

A mutable mapping storage for the user's needs.

def run( self, future: collections.abc.Coroutine[typing.Any, None, None], debug: bool = False) -> None:
134    def run(
135        self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False
136    ) -> None:
137        loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop()
138        try:
139            if not loop.is_running():
140                loop.set_debug(debug)
141                loop.run_until_complete(future)
142
143        except Exception as exc:
144            raise RuntimeError(f"Failed to run {future.__qualname__}") from exc
145
146        except KeyboardInterrupt:
147            _LOG.warn("Unexpected Keyboard interrupt. Exiting.")
148            return

Runs a coroutine function until its complete.

This is equivalent to asyncio.get_event_loop().run_until_complete(...)

Parameters
  • future (collections.Coroutine[None, None, None]): A coroutine object.
  • debug (bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
    await fetch(...)

# Run the coroutine.
client.run(main())
async def fetch_current_user_memberships(self, access_token: str, /) -> aiobungie.crates.user.User:
152    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
153        """Fetch and return a user object of the bungie net user associated with account.
154
155        .. warning::
156            This method requires OAuth2 scope and a Bearer access token.
157
158        Parameters
159        ----------
160        access_token : `str`
161            A valid Bearer access token for the authorization.
162
163        Returns
164        -------
165        `aiobungie.crates.user.User`
166            A user object includes the Destiny memberships and Bungie.net user.
167        """
168        resp = await self.rest.fetch_current_user_memberships(access_token)
169
170        return self.factory.deserialize_user(resp)

Fetch and return a user object of the bungie net user associated with account.

This method requires OAuth2 scope and a Bearer access token.

Parameters
  • access_token (str): A valid Bearer access token for the authorization.
Returns
  • aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
async def fetch_bungie_user(self, id: int, /) -> aiobungie.crates.user.BungieUser:
172    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
173        """Fetch a Bungie user by their BungieNet id.
174
175        .. note::
176            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
177            for other memberships.
178
179        Parameters
180        ----------
181        id: `int`
182            The user id.
183
184        Returns
185        -------
186        `aiobungie.crates.user.BungieUser`
187            A Bungie user.
188
189        Raises
190        ------
191        `aiobungie.error.NotFound`
192            The user was not found.
193        """
194        payload = await self.rest.fetch_bungie_user(id)
195
196        return self.factory.deserialize_bungie_user(payload)

Fetch a Bungie user by their BungieNet id.

This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id for other memberships.

Parameters
  • id (int): The user id.
Returns
  • aiobungie.crates.user.BungieUser: A Bungie user.
Raises
async def search_users( self, name: str, /) -> Iterator[aiobungie.crates.user.SearchableDestinyUser]:
198    async def search_users(
199        self, name: str, /
200    ) -> iterators.Iterator[user.SearchableDestinyUser]:
201        """Search for players and return all players that matches the same name.
202
203        Parameters
204        ----------
205        name : `buildins.str`
206            The user name.
207
208        Returns
209        -------
210        `aiobungie.iterators.Iterator[aiobungie.crates.DestinyMembership]`
211            A sequence of destiny memberships.
212        """
213        payload = await self.rest.search_users(name)
214
215        return iterators.Iterator(
216            [
217                self.factory.deserialize_searched_user(user)
218                for user in payload["searchResults"]
219            ]
220        )

Search for players and return all players that matches the same name.

Parameters
  • name (buildins.str): The user name.
Returns
async def fetch_user_themes(self) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
222    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
223        """Fetch all available user themes.
224
225        Returns
226        -------
227        `collections.Sequence[aiobungie.crates.user.UserThemes]`
228            A sequence of user themes.
229        """
230        data = await self.rest.fetch_user_themes()
231
232        return self.factory.deserialize_user_themes(data)

Fetch all available user themes.

Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
async def fetch_hard_types( self, credential: int, type: Union[int, CredentialType] = <CredentialType.STEAMID: 12>, /) -> aiobungie.crates.user.HardLinkedMembership:
234    async def fetch_hard_types(
235        self,
236        credential: int,
237        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
238        /,
239    ) -> user.HardLinkedMembership:
240        """Gets any hard linked membership given a credential.
241        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
242        Cross Save aware.
243
244        Parameters
245        ----------
246        credential: `int`
247            A valid SteamID64
248        type: `aiobungie.CredentialType`
249            The credential type. This must not be changed
250            Since its only credential that works "currently"
251
252        Returns
253        -------
254        `aiobungie.crates.user.HardLinkedMembership`
255            Information about the hard linked data.
256        """
257
258        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
259
260        return user.HardLinkedMembership(
261            id=int(payload["membershipId"]),
262            type=enums.MembershipType(payload["membershipType"]),
263            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
264        )

Gets any hard linked membership given a credential. Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
  • credential (int): A valid SteamID64
  • type (aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
  • aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
async def fetch_membership_from_id( self, id: int, /, type: Union[int, MembershipType] = <MembershipType.NONE: 0>) -> aiobungie.crates.user.User:
266    async def fetch_membership_from_id(
267        self,
268        id: int,
269        /,
270        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
271    ) -> user.User:
272        """Fetch Bungie user's memberships from their id.
273
274        Notes
275        -----
276        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
277        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
278        see `aiobungie.crates.user.DestinyMembership` for more details.
279        * If you only want the bungie user. Consider using `Client.fetch_user` method.
280
281        Parameters
282        ----------
283        id : `int`
284            The user's id.
285        type : `aiobungie.MembershipType`
286            The user's membership type.
287
288        Returns
289        -------
290        `aiobungie.crates.User`
291            A Bungie user with their membership types.
292
293        Raises
294        ------
295        aiobungie.NotFound
296            The requested user was not found.
297        """
298        payload = await self.rest.fetch_membership_from_id(id, type)
299
300        return self.factory.deserialize_user(payload)

Fetch Bungie user's memberships from their id.

Notes
  • This returns both BungieNet membership and a sequence of the player's DestinyMemberships Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, see aiobungie.crates.user.DestinyMembership for more details.
  • If you only want the bungie user. Consider using Client.fetch_user method.
Parameters
Returns
Raises
async def fetch_user_credentials( self, access_token: str, membership_id: int, /) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
302    async def fetch_user_credentials(
303        self, access_token: str, membership_id: int, /
304    ) -> collections.Sequence[user.UserCredentials]:
305        """Fetch an array of credential types attached to the requested account.
306
307        .. note::
308            This method require OAuth2 Bearer access token.
309
310        Parameters
311        ----------
312        access_token : `str`
313            The bearer access token associated with the bungie account.
314        membership_id : `int`
315            The id of the membership to return.
316
317        Returns
318        -------
319        `collections.Sequence[aiobungie.crates.UserCredentials]`
320            A sequence of the attached user credentials.
321
322        Raises
323        ------
324        `aiobungie.Unauthorized`
325            The access token was wrong or no access token passed.
326        """
327        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
328
329        return self.factory.deserialize_user_credentials(resp)

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def fetch_profile( self, member_id: int, type: Union[int, MembershipType], components: list[ComponentType], auth: Optional[str] = None) -> aiobungie.crates.components.Component:
333    async def fetch_profile(
334        self,
335        member_id: int,
336        type: typedefs.IntAnd[enums.MembershipType],
337        components: list[enums.ComponentType],
338        auth: typing.Optional[str] = None,
339    ) -> components.Component:
340        """
341        Fetch a bungie profile passing components to the request.
342
343        Parameters
344        ----------
345        member_id: `int`
346            The member's id.
347        type: `aiobungie.MembershipType`
348            A valid membership type.
349        components : `list[aiobungie.ComponentType]`
350            List of profile components to collect and return.
351
352        Other Parameters
353        ----------------
354        auth : `typing.Optional[str]`
355            A Bearer access_token to make the request with.
356            This is optional and limited to components that only requires an Authorization token.
357
358        Returns
359        --------
360        `aiobungie.crates.Component`
361            A Destiny 2 player profile with its components.
362            Only passed components will be available if they exists. Otherwise they will be `None`
363
364        Raises
365        ------
366        `aiobungie.MembershipTypeError`
367            The provided membership type was invalid.
368        """
369        data = await self.rest.fetch_profile(member_id, type, components, auth)
370        return self.factory.deserialize_components(data)

Fetch a bungie profile passing components to the request.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
  • aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will be None
Raises
async def fetch_linked_profiles( self, member_id: int, member_type: Union[int, MembershipType], /, *, all: bool = False) -> aiobungie.crates.profile.LinkedProfile:
372    async def fetch_linked_profiles(
373        self,
374        member_id: int,
375        member_type: typedefs.IntAnd[enums.MembershipType],
376        /,
377        *,
378        all: bool = False,
379    ) -> profile.LinkedProfile:
380        """Returns a summary information about all profiles linked to the requested member.
381
382        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
383
384        .. note::
385            It will only return linked accounts whose linkages you are allowed to view.
386
387        Parameters
388        ----------
389        member_id : `int`
390            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
391        member_type : `aiobungie.MembershipType`
392            The type for the membership whose linked Destiny account you want to return.
393
394        Other Parameters
395        ----------------
396        all : `bool`
397            If provided and set to `True`, All memberships regardless
398            of whether they're obscured by overrides will be returned,
399
400            If provided and set to `False`, Only available memberships will be returned.
401            The default for this is `False`.
402
403        Returns
404        -------
405        `aiobungie.crates.profile.LinkedProfile`
406            A linked profile object.
407        """
408        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
409
410        return self.factory.deserialize_linked_profiles(resp)

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
  • member_id (int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
  • member_type (aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether they're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
  • aiobungie.crates.profile.LinkedProfile: A linked profile object.
async def fetch_player( self, name: str, code: int, /, type: Union[int, MembershipType] = <MembershipType.ALL: -1>) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
412    async def fetch_player(
413        self,
414        name: str,
415        code: int,
416        /,
417        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
418    ) -> collections.Sequence[user.DestinyMembership]:
419        """Fetch a Destiny 2 player's memberships.
420
421        Parameters
422        -----------
423        name: `str`
424            The unique Bungie player name.
425        code : `int`
426            The unique Bungie display name code.
427        type: `aiobungie.internal.enums.MembershipType`
428            The player's membership type, e,g. XBOX, STEAM, PSN
429
430        Returns
431        --------
432        `collections.Sequence[aiobungie.crates.DestinyMembership]`
433            A sequence of the found Destiny 2 player memberships.
434            An empty sequence will be returned if no one found.
435
436        Raises
437        ------
438        `aiobungie.MembershipTypeError`
439            The provided membership type was invalid.
440        """
441        resp = await self.rest.fetch_player(name, code, type)
442
443        return self.factory.deserialize_destiny_memberships(resp)

Fetch a Destiny 2 player's memberships.

Parameters
  • name (str): The unique Bungie player name.
  • code (int): The unique Bungie display name code.
  • type (MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
Raises
async def fetch_character( self, member_id: int, membership_type: Union[int, MembershipType], character_id: int, components: list[ComponentType], auth: Optional[str] = None) -> aiobungie.crates.components.CharacterComponent:
445    async def fetch_character(
446        self,
447        member_id: int,
448        membership_type: typedefs.IntAnd[enums.MembershipType],
449        character_id: int,
450        components: list[enums.ComponentType],
451        auth: typing.Optional[str] = None,
452    ) -> components.CharacterComponent:
453        """Fetch a Destiny 2 character.
454
455        Parameters
456        ----------
457        member_id: `int`
458            A valid bungie member id.
459        character_id: `int`
460            The Destiny character id to retrieve.
461        membership_type: `aiobungie.internal.enums.MembershipType`
462            The member's membership type.
463        components: `list[aiobungie.ComponentType]`
464            Multiple arguments of character components to collect and return.
465
466        Other Parameters
467        ----------------
468        auth : `typing.Optional[str]`
469            A Bearer access_token to make the request with.
470            This is optional and limited to components that only requires an Authorization token.
471
472        Returns
473        -------
474        `aiobungie.crates.CharacterComponent`
475            A Bungie character component.
476
477        `aiobungie.MembershipTypeError`
478            The provided membership type was invalid.
479        """
480        resp = await self.rest.fetch_character(
481            member_id, membership_type, character_id, components, auth
482        )
483
484        return self.factory.deserialize_character_component(resp)

Fetch a Destiny 2 character.

Parameters
  • member_id (int): A valid bungie member id.
  • character_id (int): The Destiny character id to retrieve.
  • membership_type (MembershipType): The member's membership type.
  • components (list[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
  • auth (typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: Union[int, MembershipType]) -> collections.abc.Sequence[aiobungie.crates.activity.ExtendedWeaponValues]:
486    async def fetch_unique_weapon_history(
487        self,
488        membership_id: int,
489        character_id: int,
490        membership_type: typedefs.IntAnd[enums.MembershipType],
491    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
492        """Fetch details about unique weapon usage for a character. Includes all exotics.
493
494        Parameters
495        ----------
496        membership_id : `int`
497            The Destiny user membership id.
498        character_id : `int`
499            The character id to retrieve.
500        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
501            The Destiny user's membership type.
502
503        Returns
504        -------
505        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
506            A sequence of the weapon's extended values.
507        """
508        resp = await self._rest.fetch_unique_weapon_history(
509            membership_id, character_id, membership_type
510        )
511
512        return [
513            self._factory.deserialize_extended_weapon_values(weapon)
514            for weapon in resp["weapons"]
515        ]

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
Returns
async def fetch_activities( self, member_id: int, character_id: int, mode: Union[int, GameMode], *, membership_type: Union[int, MembershipType] = <MembershipType.ALL: -1>, page: int = 0, limit: int = 250) -> Iterator[aiobungie.crates.activity.Activity]:
519    async def fetch_activities(
520        self,
521        member_id: int,
522        character_id: int,
523        mode: typedefs.IntAnd[enums.GameMode],
524        *,
525        membership_type: typedefs.IntAnd[
526            enums.MembershipType
527        ] = enums.MembershipType.ALL,
528        page: int = 0,
529        limit: int = 250,
530    ) -> iterators.Iterator[activity.Activity]:
531        """Fetch a Destiny 2 activity for the specified character id.
532
533        Parameters
534        ----------
535        member_id: `int`
536            The user id that starts with `4611`.
537        character_id: `int`
538            The id of the character to retrieve the activities for.
539        mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]`
540            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
541
542        Other Parameters
543        ----------------
544        membership_type: `aiobungie.internal.enums.MembershipType`
545            The Member ship type, if nothing was passed than it will return all.
546        page: int
547            The page number. Default is `0`
548        limit: int
549            Limit the returned result. Default is `250`.
550
551        Returns
552        -------
553        `aiobungie.iterators.Iterator[aiobungie.crates.Activity]`
554            An iterator of the player's activities.
555
556        Raises
557        ------
558        `aiobungie.MembershipTypeError`
559            The provided membership type was invalid.
560        """
561        resp = await self.rest.fetch_activities(
562            member_id,
563            character_id,
564            mode,
565            membership_type=membership_type,
566            page=page,
567            limit=limit,
568        )
569
570        return self.factory.deserialize_activities(resp)

Fetch a Destiny 2 activity for the specified character id.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve the activities for.
  • mode (aiobungie.typedefs.IntAnd[GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
  • membership_type (MembershipType): The Member ship type, if nothing was passed than it will return all.
  • page (int): The page number. Default is 0
  • limit (int): Limit the returned result. Default is 250.
Returns
Raises
async def fetch_post_activity(self, instance_id: int, /) -> aiobungie.crates.activity.PostActivity:
572    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
573        """Fetch a post activity details.
574
575        Parameters
576        ----------
577        instance_id: `int`
578            The activity instance id.
579
580        Returns
581        -------
582        `aiobungie.crates.PostActivity`
583           A post activity object.
584        """
585        resp = await self.rest.fetch_post_activity(instance_id)
586
587        return self.factory.deserialize_post_activity(resp)

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: Union[int, MembershipType]) -> Iterator[aiobungie.crates.activity.AggregatedActivity]:
589    async def fetch_aggregated_activity_stats(
590        self,
591        character_id: int,
592        membership_id: int,
593        membership_type: typedefs.IntAnd[enums.MembershipType],
594    ) -> iterators.Iterator[activity.AggregatedActivity]:
595        """Fetch aggregated activity stats for a character.
596
597        Parameters
598        ----------
599        character_id: `int`
600            The id of the character to retrieve the activities for.
601        membership_id: `int`
602            The id of the user that started with `4611`.
603        membership_type: `aiobungie.internal.enums.MembershipType`
604            The Member ship type.
605
606        Returns
607        -------
608        `aiobungie.iterators.Iterator[aiobungie.crates.AggregatedActivity]`
609            An iterator of the player's activities.
610
611        Raises
612        ------
613        `aiobungie.MembershipTypeError`
614            The provided membership type was invalid.
615        """
616        resp = await self.rest.fetch_aggregated_activity_stats(
617            character_id, membership_id, membership_type
618        )
619
620        return self.factory.deserialize_aggregated_activities(resp)

Fetch aggregated activity stats for a character.

Parameters
  • character_id (int): The id of the character to retrieve the activities for.
  • membership_id (int): The id of the user that started with 4611.
  • membership_type (MembershipType): The Member ship type.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: Optional[str] = None) -> aiobungie.crates.clans.Clan:
624    async def fetch_clan_from_id(
625        self,
626        id: int,
627        /,
628        access_token: typing.Optional[str] = None,
629    ) -> clans.Clan:
630        """Fetch a Bungie Clan by its id.
631
632        Parameters
633        -----------
634        id: `int`
635            The clan id.
636
637        Returns
638        --------
639        `aiobungie.crates.Clan`
640            An Bungie clan.
641
642        Raises
643        ------
644        `aiobungie.NotFound`
645            The clan was not found.
646        """
647        resp = await self.rest.fetch_clan_from_id(id, access_token)
648
649        return self.factory.deserialize_clan(resp)

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Returns
Raises
async def fetch_clan( self, name: str, /, access_token: Optional[str] = None, *, type: Union[int, GroupType] = <GroupType.CLAN: 1>) -> aiobungie.crates.clans.Clan:
651    async def fetch_clan(
652        self,
653        name: str,
654        /,
655        access_token: typing.Optional[str] = None,
656        *,
657        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
658    ) -> clans.Clan:
659        """Fetch a Clan by its name.
660        This method will return the first clan found with given name.
661
662        Parameters
663        ----------
664        name: `str`
665            The clan name
666
667        Other Parameters
668        ----------------
669        access_token : `typing.Optional[str]`
670            An optional access token to make the request with.
671
672            If the token was bound to a member of the clan,
673            This field `aiobungie.crates.Clan.current_user_membership` will be available
674            and will return the membership of the user who made this request.
675        type : `aiobungie.GroupType`
676            The group type, Default is aiobungie.GroupType.CLAN.
677
678        Returns
679        -------
680        `aiobungie.crates.Clan`
681            A Bungie clan.
682
683        Raises
684        ------
685        `aiobungie.NotFound`
686            The clan was not found.
687        """
688        resp = await self.rest.fetch_clan(name, access_token, type=type)
689
690        return self.factory.deserialize_clan(resp)

Fetch a Clan by its name. This method will return the first clan found with given name.

Parameters
  • name (str): The clan name
Other Parameters
Returns
Raises
async def fetch_clan_conversations( self, clan_id: int, /) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
692    async def fetch_clan_conversations(
693        self, clan_id: int, /
694    ) -> collections.Sequence[clans.ClanConversation]:
695        """Fetch the conversations/chat channels of the given clan id.
696
697        Parameters
698        ----------
699        clan_id : `int`
700            The clan id.
701
702        Returns
703        `collections.Sequence[aiobungie.crates.ClanConversation]`
704            A sequence of the clan chat channels.
705        """
706        resp = await self.rest.fetch_clan_conversations(clan_id)
707
708        return self.factory.deserialize_clan_conversations(resp)

Fetch the conversations/chat channels of the given clan id.

Parameters
async def fetch_clan_admins( self, clan_id: int, /) -> Iterator[aiobungie.crates.clans.ClanMember]:
710    async def fetch_clan_admins(
711        self, clan_id: int, /
712    ) -> iterators.Iterator[clans.ClanMember]:
713        """Fetch the clan founder and admins.
714
715        Parameters
716        ----------
717        clan_id : `int`
718            The clan id.
719
720        Returns
721        -------
722        `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]`
723            An iterator over the found clan admins and founder.
724
725        Raises
726        ------
727        `aiobungie.NotFound`
728            The requested clan was not found.
729        """
730        resp = await self.rest.fetch_clan_admins(clan_id)
731
732        return self.factory.deserialize_clan_members(resp)

Fetch the clan founder and admins.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_groups_for_member( self, member_id: int, member_type: Union[int, MembershipType], /, *, filter: int = 0, group_type: GroupType = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
734    async def fetch_groups_for_member(
735        self,
736        member_id: int,
737        member_type: typedefs.IntAnd[enums.MembershipType],
738        /,
739        *,
740        filter: int = 0,
741        group_type: enums.GroupType = enums.GroupType.CLAN,
742    ) -> collections.Sequence[clans.GroupMember]:
743        """Fetch information about the groups that a given member has joined.
744
745        Parameters
746        ----------
747        member_id : `int`
748            The member's id
749        member_type : `aiobungie.MembershipType`
750            The member's membership type.
751
752        Other Parameters
753        ----------------
754        filter : `int`
755            Filter apply to list of joined groups. This Default to `0`
756        group_type : `aiobungie.GroupType`
757            The group's type.
758            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
759
760        Returns
761        -------
762        `collections.Sequence[aiobungie.crates.GroupMember]`
763            A sequence of joined groups for the fetched member.
764        """
765        resp = await self.rest.fetch_groups_for_member(
766            member_id, member_type, filter=filter, group_type=group_type
767        )
768
769        return [
770            self.factory.deserialize_group_member(group) for group in resp["results"]
771        ]

Fetch information about the groups that a given member has joined.

Parameters
Other Parameters
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: Union[int, MembershipType], /, *, filter: int = 0, group_type: Union[int, GroupType] = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
773    async def fetch_potential_groups_for_member(
774        self,
775        member_id: int,
776        member_type: typedefs.IntAnd[enums.MembershipType],
777        /,
778        *,
779        filter: int = 0,
780        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
781    ) -> collections.Sequence[clans.GroupMember]:
782        """Fetch the potential groups for a clan member.
783
784        Parameters
785        ----------
786        member_id : `int`
787            The member's id
788        member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
789            The member's membership type.
790
791        Other Parameters
792        ----------------
793        filter : `int`
794            Filter apply to list of joined groups. This Default to `0`
795        group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]`
796            The group's type.
797            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
798
799        Returns
800        -------
801        `collections.Sequence[aiobungie.crates.GroupMember]`
802            A sequence of joined potential groups for the fetched member.
803        """
804        resp = await self.rest.fetch_potential_groups_for_member(
805            member_id, member_type, filter=filter, group_type=group_type
806        )
807
808        return [
809            self.factory.deserialize_group_member(group) for group in resp["results"]
810        ]

Fetch the potential groups for a clan member.

Parameters
Other Parameters
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: Optional[str] = None, type: Union[int, MembershipType] = <MembershipType.NONE: 0>) -> Iterator[aiobungie.crates.clans.ClanMember]:
812    async def fetch_clan_members(
813        self,
814        clan_id: int,
815        /,
816        *,
817        name: typing.Optional[str] = None,
818        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
819    ) -> iterators.Iterator[clans.ClanMember]:
820        """Fetch Bungie clan members.
821
822        Parameters
823        ----------
824        clan_id : `int`
825            The clans id
826
827        Other Parameters
828        ----------------
829        name : `typing.Optional[str]`
830            If provided, Only players matching this name will be returned.
831        type : `aiobungie.MembershipType`
832            An optional clan member's membership type.
833            This parameter is used to filter the returned results
834            by the provided membership, For an example XBox memberships only,
835            Otherwise will return all memberships.
836
837        Returns
838        -------
839        `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]`
840            An iterator over the bungie clan members.
841
842        Raises
843        ------
844        `aiobungie.NotFound`
845            The clan was not found.
846        """
847        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
848
849        return self.factory.deserialize_clan_members(resp)

Fetch Bungie clan members.

Parameters
  • clan_id (int): The clans id
Other Parameters
  • name (typing.Optional[str]): If provided, Only players matching this name will be returned.
  • type (aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
Raises
async def fetch_clan_banners(self) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
851    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
852        """Fetch the clan banners.
853
854        Returns
855        -------
856        `collections.Sequence[aiobungie.crates.ClanBanner]`
857            A sequence of the clan banners.
858        """
859        resp = await self.rest.fetch_clan_banners()
860
861        return self.factory.deserialize_clan_banners(resp)

Fetch the clan banners.

Returns
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, MembershipType]) -> aiobungie.crates.clans.Clan:
864    async def kick_clan_member(
865        self,
866        access_token: str,
867        /,
868        group_id: int,
869        membership_id: int,
870        membership_type: typedefs.IntAnd[enums.MembershipType],
871    ) -> clans.Clan:
872        """Kick a member from the clan.
873
874        .. note::
875            This request requires OAuth2: oauth2: `AdminGroups` scope.
876
877        Parameters
878        ----------
879        access_token : `str`
880            The bearer access token associated with the bungie account.
881        group_id: `int`
882            The group id.
883        membership_id : `int`
884            The member id to kick.
885        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
886            The member's membership type.
887
888        Returns
889        -------
890        `aiobungie.crates.clan.Clan`
891            The clan that the member was kicked from.
892        """
893        resp = await self.rest.kick_clan_member(
894            access_token,
895            group_id=group_id,
896            membership_id=membership_id,
897            membership_type=membership_type,
898        )
899
900        return self.factory.deserialize_clan(resp)

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
  • aiobungie.crates.clan.Clan: The clan that the member was kicked from.
async def fetch_clan_weekly_rewards(self, clan_id: int) -> aiobungie.crates.milestones.Milestone:
902    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
903        """Fetch a Bungie clan's weekly reward state.
904
905        Parameters
906        ----------
907        clan_id : `int`
908            The clan's id.
909
910        Returns
911        -------
912        `aiobungie.crates.Milestone`
913            A runtime status of the clan's milestone data.
914        """
915
916        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
917
918        return self.factory.deserialize_milestone(resp)

Fetch a Bungie clan's weekly reward state.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_inventory_item(self, hash: int, /) -> aiobungie.crates.entity.InventoryEntity:
922    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
923        """Fetch a static inventory item entity given a its hash.
924
925        Parameters
926        ----------
927        hash: `int`
928            Inventory item's hash.
929
930        Returns
931        -------
932        `aiobungie.crates.InventoryEntity`
933            A bungie inventory item.
934        """
935        resp = await self.rest.fetch_inventory_item(hash)
936
937        return self.factory.deserialize_inventory_entity(resp)

Fetch a static inventory item entity given a its hash.

Parameters
  • hash (int): Inventory item's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> aiobungie.crates.entity.ObjectiveEntity:
939    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
940        """Fetch a Destiny objective entity given a its hash.
941
942        Parameters
943        ----------
944        hash: `int`
945            objective's hash.
946
947        Returns
948        -------
949        `aiobungie.crates.ObjectiveEntity`
950            An objective entity item.
951        """
952        resp = await self.rest.fetch_objective_entity(hash)
953
954        return self.factory.deserialize_objective_entity(resp)

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> Iterator[aiobungie.crates.entity.SearchableEntity]:
956    async def search_entities(
957        self, name: str, entity_type: str, *, page: int = 0
958    ) -> iterators.Iterator[entity.SearchableEntity]:
959        """Search for Destiny2 entities given a name and its type.
960
961        Parameters
962        ----------
963        name : `str`
964            The name of the entity, i.e., Thunderlord, One thousand voices.
965        entity_type : `str`
966            The type of the entity, AKA Definition,
967            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
968
969        Other Parameters
970        ----------------
971        page : `int`
972            An optional page to return. Default to 0.
973
974        Returns
975        -------
976        `aiobungie.iterators.Iterator[aiobungie.crates.SearchableEntity]`
977            An iterator over the found results matching the provided name.
978        """
979        resp = await self.rest.search_entities(name, entity_type, page=page)
980
981        return self.factory.deserialize_inventory_results(resp)

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition for emblems, weapons, and other inventory items.
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_fireteams( self, activity_type: Union[int, FireteamActivity], *, platform: Union[int, FireteamPlatform] = <FireteamPlatform.ANY: 0>, language: Union[FireteamLanguage, str] = <FireteamLanguage.ALL: >, date_range: int = 0, page: int = 0, slots_filter: int = 0) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
 985    async def fetch_fireteams(
 986        self,
 987        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
 988        *,
 989        platform: typedefs.IntAnd[
 990            fireteams.FireteamPlatform
 991        ] = fireteams.FireteamPlatform.ANY,
 992        language: typing.Union[
 993            fireteams.FireteamLanguage, str
 994        ] = fireteams.FireteamLanguage.ALL,
 995        date_range: int = 0,
 996        page: int = 0,
 997        slots_filter: int = 0,
 998    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
 999        """Fetch public Bungie fireteams with open slots.
1000
1001        Parameters
1002        ----------
1003        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1004            The fireteam activity type.
1005
1006        Other Parameters
1007        ----------------
1008        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1009            If this is provided. Then the results will be filtered with the given platform.
1010            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1011        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1012            A locale language to filter the used language in that fireteam.
1013            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1014        date_range : `int`
1015            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1016        page : `int`
1017            The page number. By default its `0` which returns all available activities.
1018        slots_filter : `int`
1019            Filter the returned fireteams based on available slots. Default is `0`
1020
1021        Returns
1022        -------
1023        `typing.Optional[collections.Sequence[fireteams.Fireteam]]`
1024            A sequence of `aiobungie.crates.Fireteam` or `None`.
1025        """
1026
1027        resp = await self.rest.fetch_fireteams(
1028            activity_type,
1029            platform=platform,
1030            language=language,
1031            date_range=date_range,
1032            page=page,
1033            slots_filter=slots_filter,
1034        )
1035
1036        return self.factory.deserialize_fireteams(resp)

Fetch public Bungie fireteams with open slots.

Parameters
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_avaliable_clan_fireteams( self, access_token: str, group_id: int, activity_type: Union[int, FireteamActivity], *, platform: Union[int, FireteamPlatform], language: Union[FireteamLanguage, str], date_range: int = 0, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
1038    async def fetch_avaliable_clan_fireteams(
1039        self,
1040        access_token: str,
1041        group_id: int,
1042        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1043        *,
1044        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1045        language: typing.Union[fireteams.FireteamLanguage, str],
1046        date_range: int = 0,
1047        page: int = 0,
1048        public_only: bool = False,
1049        slots_filter: int = 0,
1050    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1051        """Fetch a clan's fireteams with open slots.
1052
1053        .. note::
1054            This method requires OAuth2: ReadGroups scope.
1055
1056        Parameters
1057        ----------
1058        access_token : `str`
1059            The bearer access token associated with the bungie account.
1060        group_id : `int`
1061            The group/clan id of the fireteam.
1062        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1063            The fireteam activity type.
1064
1065        Other Parameters
1066        ----------------
1067        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1068            If this is provided. Then the results will be filtered with the given platform.
1069            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1070        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1071            A locale language to filter the used language in that fireteam.
1072            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1073        date_range : `int`
1074            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1075        page : `int`
1076            The page number. By default its `0` which returns all available activities.
1077        public_only: `bool`
1078            If set to True, Then only public fireteams will be returned.
1079        slots_filter : `int`
1080            Filter the returned fireteams based on available slots. Default is `0`
1081
1082        Returns
1083        -------
1084        `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]`
1085            A sequence of  fireteams found in the clan.
1086            `None` will be returned if nothing was found.
1087        """
1088        resp = await self.rest.fetch_avaliable_clan_fireteams(
1089            access_token,
1090            group_id,
1091            activity_type,
1092            platform=platform,
1093            language=language,
1094            date_range=date_range,
1095            page=page,
1096            public_only=public_only,
1097            slots_filter=slots_filter,
1098        )
1099
1100        return self.factory.deserialize_fireteams(resp)

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to 0.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
  • typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]: A sequence of fireteams found in the clan. None will be returned if nothing was found.
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> aiobungie.crates.fireteams.AvailableFireteam:
1102    async def fetch_clan_fireteam(
1103        self, access_token: str, fireteam_id: int, group_id: int
1104    ) -> fireteams.AvailableFireteam:
1105        """Fetch a specific clan fireteam.
1106
1107        .. note::
1108            This method requires OAuth2: ReadGroups scope.
1109
1110        Parameters
1111        ----------
1112        access_token : `str`
1113            The bearer access token associated with the bungie account.
1114        group_id : `int`
1115            The group/clan id to fetch the fireteam from.
1116        fireteam_id : `int`
1117            The fireteam id to fetch.
1118
1119        Returns
1120        -------
1121        `typing.Optional[aiobungie.crates.AvailableFireteam]`
1122            A sequence of available fireteams objects if exists. else `None` will be returned.
1123        """
1124        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1125
1126        return self.factory.deserialize_available_fireteams(
1127            resp, no_results=True
1128        )  # type: ignore[return-value]

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: Union[int, FireteamPlatform], language: Union[FireteamLanguage, str], filtered: bool = True, page: int = 0) -> collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]:
1130    async def fetch_my_clan_fireteams(
1131        self,
1132        access_token: str,
1133        group_id: int,
1134        *,
1135        include_closed: bool = True,
1136        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1137        language: typing.Union[fireteams.FireteamLanguage, str],
1138        filtered: bool = True,
1139        page: int = 0,
1140    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1141        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1142
1143        .. note::
1144            This method requires OAuth2: ReadGroups scope.
1145
1146        Parameters
1147        ----------
1148        access_token : str
1149            The bearer access token associated with the bungie account.
1150        group_id : int
1151            The group/clan id to fetch.
1152
1153        Other Parameters
1154        ----------------
1155        include_closed : bool
1156            If provided and set to True, It will also return closed fireteams.
1157            If provided and set to False, It will only return public fireteams. Default is True.
1158        platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]
1159            If this is provided. Then the results will be filtered with the given platform.
1160            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1161        language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]
1162            A locale language to filter the used language in that fireteam.
1163            Defaults to aiobungie.crates.FireteamLanguage.ALL
1164        filtered : bool
1165            If set to True, it will filter by clan. Otherwise not. Default is True.
1166        page : int
1167            The page number. By default its 0 which returns all available activities.
1168
1169        Returns
1170        -------
1171        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1172            A sequence of available fireteams objects if exists. else `None` will be returned.
1173        """
1174        resp = await self.rest.fetch_my_clan_fireteams(
1175            access_token,
1176            group_id,
1177            include_closed=include_closed,
1178            platform=platform,
1179            language=language,
1180            filtered=filtered,
1181            page=page,
1182        )
1183
1184        return self.factory.deserialize_available_fireteams(resp)  # type: ignore[return-value]

A method that's similar to fetch_fireteams but requires OAuth2.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.typedefs.IntAnd[FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_friends( self, access_token: str, /) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
1188    async def fetch_friends(
1189        self, access_token: str, /
1190    ) -> collections.Sequence[friends.Friend]:
1191        """Fetch bungie friend list.
1192
1193        .. note::
1194            This requests OAuth2: ReadUserData scope.
1195
1196        Parameters
1197        -----------
1198        access_token : `str`
1199            The bearer access token associated with the bungie account.
1200
1201        Returns
1202        -------
1203        `collections.Sequence[aiobungie.crates.Friend]`
1204            A sequence of the friends associated with that access token.
1205        """
1206
1207        resp = await self.rest.fetch_friends(access_token)
1208
1209        return self.factory.deserialize_friends(resp)

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> aiobungie.crates.friends.FriendRequestView:
1211    async def fetch_friend_requests(
1212        self, access_token: str, /
1213    ) -> friends.FriendRequestView:
1214        """Fetch pending bungie friend requests queue.
1215
1216        .. note::
1217            This requests OAuth2: ReadUserData scope.
1218
1219        Parameters
1220        -----------
1221        access_token : `str`
1222            The bearer access token associated with the bungie account.
1223
1224        Returns
1225        -------
1226        `aiobungie.crates.FriendRequestView`
1227            A friend requests view of that associated access token.
1228        """
1229
1230        resp = await self.rest.fetch_friend_requests(access_token)
1231
1232        return self.factory.deserialize_friend_requests(resp)

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_application(self, appid: int, /) -> aiobungie.crates.application.Application:
1236    async def fetch_application(self, appid: int, /) -> application.Application:
1237        """Fetch a Bungie application.
1238
1239        Parameters
1240        -----------
1241        appid: `int`
1242            The application id.
1243
1244        Returns
1245        --------
1246        `aiobungie.crates.Application`
1247            A Bungie application.
1248        """
1249        resp = await self.rest.fetch_application(appid)
1250
1251        return self.factory.deserialize_app(resp)

Fetch a Bungie application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_public_milestone_content( self, milestone_hash: int, /) -> aiobungie.crates.milestones.MilestoneContent:
1255    async def fetch_public_milestone_content(
1256        self, milestone_hash: int, /
1257    ) -> milestones.MilestoneContent:
1258        """Fetch the milestone content given its hash.
1259
1260        Parameters
1261        ----------
1262        milestone_hash : `int`
1263            The milestone hash.
1264
1265        Returns
1266        -------
1267        `aiobungie.crates.milestones.MilestoneContent`
1268            A milestone content object.
1269        """
1270        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1271
1272        return self.factory.deserialize_public_milestone_content(resp)

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
  • aiobungie.crates.milestones.MilestoneContent: A milestone content object.
@typing.final
class ClosedReasons(aiobungie.Flag):
781@typing.final
782class ClosedReasons(Flag):
783    """A Flags enumeration representing the reasons why a person can't join this user's fireteam."""
784
785    NONE = 0
786    MATCHMAKING = 1 << 0
787    LOADING = 1 << 1
788    SOLO = 1 << 2
789    """The activity is required to be played solo."""
790    INTERNAL_REASONS = 1 << 3
791    """
792    The user can't be joined for one of a variety of internal reasons.
793    Basically, the game can't let you join at this time,
794    but for reasons that aren't under the control of this user
795    """
796    DISALLOWED_BY_GAME_STATE = 1 << 4
797    """The user's current activity/quest/other transitory game state is preventing joining."""
798    OFFLINE = 32768
799    """The user appears offline."""

A Flags enumeration representing the reasons why a person can't join this user's fireteam.

NONE = <ClosedReasons.NONE: 0>
MATCHMAKING = <ClosedReasons.MATCHMAKING: 1>
LOADING = <ClosedReasons.LOADING: 2>
SOLO = <ClosedReasons.SOLO: 4>

The activity is required to be played solo.

INTERNAL_REASONS = <ClosedReasons.INTERNAL_REASONS: 8>

The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user

DISALLOWED_BY_GAME_STATE = <ClosedReasons.DISALLOWED_BY_GAME_STATE: 16>

The user's current activity/quest/other transitory game state is preventing joining.

OFFLINE = <ClosedReasons.OFFLINE: 32768>

The user appears offline.

Inherited Members
Flag
name
value
@typing.final
class ComponentFields(aiobungie.Enum):
74@typing.final
75class ComponentFields(enums.Enum):
76    """An enum that provides fields found in a base component response."""
77
78    PRIVACY = ComponentPrivacy
79    DISABLED = False

An enum that provides fields found in a base component response.

PRIVACY = <ComponentFields.PRIVACY: <enum 'ComponentPrivacy'>>
DISABLED = <ComponentFields.DISABLED: False>
Inherited Members
Enum
name
value
@typing.final
class ComponentPrivacy(builtins.int, aiobungie.Enum):
65@typing.final
66class ComponentPrivacy(int, enums.Enum):
67    """An enum the provides privacy settings for profile components."""
68
69    NONE = 0
70    PUBLIC = 1
71    PRIVATE = 2

An enum the provides privacy settings for profile components.

NONE = <ComponentPrivacy.NONE: 0>
PUBLIC = <ComponentPrivacy.PUBLIC: 1>
PRIVATE = <ComponentPrivacy.PRIVATE: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ComponentType(aiobungie.Enum):
358@typing.final
359class ComponentType(Enum):
360    """An Enum for Destiny 2 profile Components."""
361
362    NONE = 0
363
364    PROFILE = 100
365    PROFILE_INVENTORIES = 102
366    PROFILE_CURRENCIES = 103
367    PROFILE_PROGRESSION = 104
368    ALL_PROFILES = (
369        PROFILE,
370        PROFILE_INVENTORIES,
371        PROFILE_CURRENCIES,
372        PROFILE_PROGRESSION,
373    )
374    """All profile components."""
375
376    VENDORS = 400
377    VENDOR_SALES = 402
378    VENDOR_RECEIPTS = 101
379    ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES)
380    """All vendor components."""
381
382    # Items
383    ITEM_INSTANCES = 300
384    ITEM_OBJECTIVES = 301
385    ITEM_PERKS = 302
386    ITEM_RENDER_DATA = 303
387    ITEM_STATS = 304
388    ITEM_SOCKETS = 305
389    ITEM_TALENT_GRINDS = 306
390    ITEM_PLUG_STATES = 308
391    ITEM_PLUG_OBJECTIVES = 309
392    ITEM_REUSABLE_PLUGS = 310
393
394    ALL_ITEMS = (
395        ITEM_PLUG_OBJECTIVES,
396        ITEM_PLUG_STATES,
397        ITEM_SOCKETS,
398        ITEM_INSTANCES,
399        ITEM_OBJECTIVES,
400        ITEM_PERKS,
401        ITEM_RENDER_DATA,
402        ITEM_STATS,
403        ITEM_TALENT_GRINDS,
404        ITEM_REUSABLE_PLUGS,
405    )
406    """All item components."""
407
408    PLATFORM_SILVER = 105
409    KIOSKS = 500
410    CURRENCY_LOOKUPS = 600
411    PRESENTATION_NODES = 700
412    COLLECTIBLES = 800
413    RECORDS = 900
414    TRANSITORY = 1000
415    METRICS = 1100
416    INVENTORIES = 102
417    STRING_VARIABLES = 1200
418    CRAFTABLES = 1300
419
420    CHARACTERS = 200
421    CHARACTER_INVENTORY = 201
422    CHARECTER_PROGRESSION = 202
423    CHARACTER_RENDER_DATA = 203
424    CHARACTER_ACTIVITIES = 204
425    CHARACTER_EQUIPMENT = 205
426    CHARACTER_LOADOUTS = 206
427
428    ALL_CHARACTERS = (
429        CHARACTERS,
430        CHARACTER_INVENTORY,
431        CHARECTER_PROGRESSION,
432        CHARACTER_RENDER_DATA,
433        CHARACTER_ACTIVITIES,
434        CHARACTER_EQUIPMENT,
435        CHARACTER_LOADOUTS,
436        RECORDS,
437    )
438    """All character components."""
439
440    ALL = (
441        *ALL_PROFILES,  # type: ignore
442        *ALL_CHARACTERS,  # type: ignore
443        *ALL_VENDORS,  # type: ignore
444        *ALL_ITEMS,  # type: ignore
445        RECORDS,
446        CURRENCY_LOOKUPS,
447        PRESENTATION_NODES,
448        COLLECTIBLES,
449        KIOSKS,
450        METRICS,
451        PLATFORM_SILVER,
452        INVENTORIES,
453        STRING_VARIABLES,
454        TRANSITORY,
455        CRAFTABLES,
456    )
457    """ALl components included."""

An Enum for Destiny 2 profile Components.

NONE = <ComponentType.NONE: 0>
PROFILE = <ComponentType.PROFILE: 100>
PROFILE_INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
PROFILE_CURRENCIES = <ComponentType.PROFILE_CURRENCIES: 103>
PROFILE_PROGRESSION = <ComponentType.PROFILE_PROGRESSION: 104>
ALL_PROFILES = <ComponentType.ALL_PROFILES: (100, 102, 103, 104)>

All profile components.

VENDORS = <ComponentType.VENDORS: 400>
VENDOR_SALES = <ComponentType.VENDOR_SALES: 402>
VENDOR_RECEIPTS = <ComponentType.VENDOR_RECEIPTS: 101>
ALL_VENDORS = <ComponentType.ALL_VENDORS: (400, 101, 402)>

All vendor components.

ITEM_INSTANCES = <ComponentType.ITEM_INSTANCES: 300>
ITEM_OBJECTIVES = <ComponentType.ITEM_OBJECTIVES: 301>
ITEM_PERKS = <ComponentType.ITEM_PERKS: 302>
ITEM_RENDER_DATA = <ComponentType.ITEM_RENDER_DATA: 303>
ITEM_STATS = <ComponentType.ITEM_STATS: 304>
ITEM_SOCKETS = <ComponentType.ITEM_SOCKETS: 305>
ITEM_TALENT_GRINDS = <ComponentType.ITEM_TALENT_GRINDS: 306>
ITEM_PLUG_STATES = <ComponentType.ITEM_PLUG_STATES: 308>
ITEM_PLUG_OBJECTIVES = <ComponentType.ITEM_PLUG_OBJECTIVES: 309>
ITEM_REUSABLE_PLUGS = <ComponentType.ITEM_REUSABLE_PLUGS: 310>
ALL_ITEMS = <ComponentType.ALL_ITEMS: (309, 308, 305, 300, 301, 302, 303, 304, 306, 310)>

All item components.

PLATFORM_SILVER = <ComponentType.PLATFORM_SILVER: 105>
KIOSKS = <ComponentType.KIOSKS: 500>
CURRENCY_LOOKUPS = <ComponentType.CURRENCY_LOOKUPS: 600>
PRESENTATION_NODES = <ComponentType.PRESENTATION_NODES: 700>
COLLECTIBLES = <ComponentType.COLLECTIBLES: 800>
RECORDS = <ComponentType.RECORDS: 900>
TRANSITORY = <ComponentType.TRANSITORY: 1000>
METRICS = <ComponentType.METRICS: 1100>
INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
STRING_VARIABLES = <ComponentType.STRING_VARIABLES: 1200>
CRAFTABLES = <ComponentType.CRAFTABLES: 1300>
CHARACTERS = <ComponentType.CHARACTERS: 200>
CHARACTER_INVENTORY = <ComponentType.CHARACTER_INVENTORY: 201>
CHARECTER_PROGRESSION = <ComponentType.CHARECTER_PROGRESSION: 202>
CHARACTER_RENDER_DATA = <ComponentType.CHARACTER_RENDER_DATA: 203>
CHARACTER_ACTIVITIES = <ComponentType.CHARACTER_ACTIVITIES: 204>
CHARACTER_EQUIPMENT = <ComponentType.CHARACTER_EQUIPMENT: 205>
CHARACTER_LOADOUTS = <ComponentType.CHARACTER_LOADOUTS: 206>
ALL_CHARACTERS = <ComponentType.ALL_CHARACTERS: (200, 201, 202, 203, 204, 205, 206, 900)>

All character components.

ALL = <ComponentType.ALL: (100, 102, 103, 104, 200, 201, 202, 203, 204, 205, 206, 900, 400, 101, 402, 309, 308, 305, 300, 301, 302, 303, 304, 306, 310, 900, 600, 700, 800, 500, 1100, 105, 102, 1200, 1000, 1300)>

ALl components included.

Inherited Members
Enum
name
value
@typing.final
class CredentialType(builtins.int, aiobungie.Enum):
663@typing.final
664class CredentialType(int, Enum):
665    """The types of the accounts system supports at bungie."""
666
667    NONE = 0
668    XUID = 1
669    PSNID = 2
670    WILD = 3
671    FAKE = 4
672    FACEBOOK = 5
673    GOOGLE = 8
674    WINDOWS = 9
675    DEMONID = 10
676    STEAMID = 12
677    BATTLENETID = 14
678    STADIAID = 16
679    TWITCHID = 18

The types of the accounts system supports at bungie.

NONE = <CredentialType.NONE: 0>
XUID = <CredentialType.XUID: 1>
PSNID = <CredentialType.PSNID: 2>
WILD = <CredentialType.WILD: 3>
FAKE = <CredentialType.FAKE: 4>
FACEBOOK = <CredentialType.FACEBOOK: 5>
GOOGLE = <CredentialType.GOOGLE: 8>
WINDOWS = <CredentialType.WINDOWS: 9>
DEMONID = <CredentialType.DEMONID: 10>
STEAMID = <CredentialType.STEAMID: 12>
BATTLENETID = <CredentialType.BATTLENETID: 14>
STADIAID = <CredentialType.STADIAID: 16>
TWITCHID = <CredentialType.TWITCHID: 18>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class DamageType(builtins.int, aiobungie.Enum):
541@typing.final
542class DamageType(int, Enum):
543    """Enums for Destiny Damage types"""
544
545    NONE = 0
546    KINETIC = 1
547    ARC = 2
548    SOLAR = 3
549    VOID = 4
550    RAID = 5
551    """This is a special damage type reserved for some raid activity encounters."""
552    STASIS = 6

Enums for Destiny Damage types

NONE = <DamageType.NONE: 0>
KINETIC = <DamageType.KINETIC: 1>
ARC = <DamageType.ARC: 2>
SOLAR = <DamageType.SOLAR: 3>
VOID = <DamageType.VOID: 4>
RAID = <DamageType.RAID: 5>

This is a special damage type reserved for some raid activity encounters.

STASIS = <DamageType.STASIS: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Difficulty(builtins.int, aiobungie.Enum):
64@typing.final
65class Difficulty(int, enums.Enum):
66    """An enum for activities difficulties."""
67
68    TRIVIAL = 0
69    EASY = 1
70    NORMAL = 2
71    CHALLENGING = 3
72    HARD = 4
73    BRAVE = 5
74    ALMOST_IMPOSSIBLE = 6
75    IMPOSSIBLE = 7

An enum for activities difficulties.

TRIVIAL = <Difficulty.TRIVIAL: 0>
EASY = <Difficulty.EASY: 1>
NORMAL = <Difficulty.NORMAL: 2>
CHALLENGING = <Difficulty.CHALLENGING: 3>
HARD = <Difficulty.HARD: 4>
BRAVE = <Difficulty.BRAVE: 5>
ALMOST_IMPOSSIBLE = <Difficulty.ALMOST_IMPOSSIBLE: 6>
IMPOSSIBLE = <Difficulty.IMPOSSIBLE: 7>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Dungeon(builtins.int, aiobungie.Enum):
160@typing.final
161class Dungeon(int, Enum):
162    """An Enum for all available Dungeon/Like missions in Destiny 2."""
163
164    NORMAL_PRESAGE = 2124066889
165    """Normal Presage"""
166
167    MASTER_PRESAGE = 4212753278
168    """Master Presage"""
169
170    HARBINGER = 1738383283
171    """Harbinger"""
172
173    PROPHECY = 4148187374
174    """Prophecy"""
175
176    MASTER_POH = 785700673
177    """Master Pit of Heresy?"""
178
179    LEGEND_POH = 785700678
180    """Legend Pit of Heresy?"""
181
182    POH = 1375089621
183    """Normal Pit of Heresy."""
184
185    SHATTERED = 2032534090
186    """Shattered Throne"""
187
188    GOA_LEGEND = 4078656646
189    """Grasp of Avarice legend."""
190
191    GOA_MASTER = 3774021532
192    """Grasp of Avarice master."""

An Enum for all available Dungeon/Like missions in Destiny 2.

NORMAL_PRESAGE = <Dungeon.NORMAL_PRESAGE: 2124066889>

Normal Presage

MASTER_PRESAGE = <Dungeon.MASTER_PRESAGE: 4212753278>

Master Presage

HARBINGER = <Dungeon.HARBINGER: 1738383283>

Harbinger

PROPHECY = <Dungeon.PROPHECY: 4148187374>

Prophecy

MASTER_POH = <Dungeon.MASTER_POH: 785700673>

Master Pit of Heresy?

LEGEND_POH = <Dungeon.LEGEND_POH: 785700678>

Legend Pit of Heresy?

POH = <Dungeon.POH: 1375089621>

Normal Pit of Heresy.

SHATTERED = <Dungeon.SHATTERED: 2032534090>

Shattered Throne

GOA_LEGEND = <Dungeon.GOA_LEGEND: 4078656646>

Grasp of Avarice legend.

GOA_MASTER = <Dungeon.GOA_MASTER: 3774021532>

Grasp of Avarice master.

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Enum(enum.Enum):
72class Enum(__enum.Enum):
73    """Builtin Python enum with extra handlings."""
74
75    @property
76    def name(self) -> str:  # type: ignore[override]
77        return self._name_
78
79    @property
80    def value(self) -> typing.Any:  # type: ignore[override]
81        return self._value_
82
83    def __str__(self) -> str:
84        return self._name_
85
86    def __repr__(self) -> str:
87        return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>"
88
89    def __int__(self) -> int:
90        if isinstance(self.value, _ITERABLE):
91            raise TypeError(
92                f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.",
93            )
94        return int(self.value)

Builtin Python enum with extra handlings.

name: str

The name of the Enum member.

value: Any

The value of the Enum member.

class Factory(aiobungie.interfaces.factory.FactoryInterface):
  61class Factory(interfaces.FactoryInterface):
  62    """The base deserialization factory class for all aiobungie objects.
  63
  64    Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them
  65    into a `aiobungie.crates` Python classes.
  66    """
  67
  68    __slots__ = ("_net",)
  69
  70    def __init__(self, net: traits.Netrunner) -> None:
  71        self._net = net
  72
  73    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
  74        return user.BungieUser(
  75            id=int(data["membershipId"]),
  76            created_at=time.clean_date(data["firstAccess"]),
  77            name=data.get("cachedBungieGlobalDisplayName", undefined.UNDEFINED),
  78            is_deleted=data["isDeleted"],
  79            about=data["about"],
  80            updated_at=time.clean_date(data["lastUpdate"]),
  81            psn_name=data.get("psnDisplayName", None),
  82            stadia_name=data.get("stadiaDisplayName", None),
  83            steam_name=data.get("steamDisplayName", None),
  84            twitch_name=data.get("twitchDisplayName", None),
  85            blizzard_name=data.get("blizzardDisplayName", None),
  86            status=data["statusText"],
  87            locale=data["locale"],
  88            picture=assets.Image(path=str(data["profilePicturePath"])),
  89            code=data.get("cachedBungieGlobalDisplayNameCode", None),
  90            unique_name=data.get("uniqueName", None),
  91            theme_id=int(data["profileTheme"]),
  92            show_activity=bool(data["showActivity"]),
  93            theme_name=data["profileThemeName"],
  94            display_title=data["userTitleDisplay"],
  95        )
  96
  97    def deserialize_partial_bungie_user(
  98        self, payload: typedefs.JSONObject
  99    ) -> user.PartialBungieUser:
 100        return user.PartialBungieUser(
 101            net=self._net,
 102            types=[
 103                enums.MembershipType(type_)
 104                for type_ in payload.get("applicableMembershipTypes", [])
 105            ],
 106            name=payload.get("displayName", undefined.UNDEFINED),
 107            id=int(payload["membershipId"]),
 108            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 109            is_public=payload["isPublic"],
 110            icon=assets.Image(payload.get("iconPath", "")),
 111            type=enums.MembershipType(payload["membershipType"]),
 112        )
 113
 114    def deserialize_destiny_membership(
 115        self, payload: typedefs.JSONObject
 116    ) -> user.DestinyMembership:
 117        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
 118        if (
 119            raw_name := payload.get("bungieGlobalDisplayName", "")
 120        ) and not typedefs.is_unknown(raw_name):
 121            name = raw_name
 122
 123        return user.DestinyMembership(
 124            net=self._net,
 125            id=int(payload["membershipId"]),
 126            name=name,
 127            code=payload.get("bungieGlobalDisplayNameCode", None),
 128            last_seen_name=payload.get("LastSeenDisplayName")
 129            or payload.get("displayName")  # noqa: W503
 130            or "",  # noqa: W503
 131            type=enums.MembershipType(payload["membershipType"]),
 132            is_public=payload["isPublic"],
 133            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 134            icon=assets.Image(payload.get("iconPath", "")),
 135            types=[
 136                enums.MembershipType(type_)
 137                for type_ in payload.get("applicableMembershipTypes", [])
 138            ],
 139        )
 140
 141    def deserialize_destiny_memberships(
 142        self, data: typedefs.JSONArray
 143    ) -> collections.Sequence[user.DestinyMembership]:
 144        return [self.deserialize_destiny_membership(membership) for membership in data]
 145
 146    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
 147        primary_membership_id: typing.Optional[int] = None
 148        if raw_primary_id := data.get("primaryMembershipId"):
 149            primary_membership_id = int(raw_primary_id)
 150
 151        return user.User(
 152            bungie=self.deserialize_bungie_user(data["bungieNetUser"]),
 153            destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]),
 154            primary_membership_id=primary_membership_id,
 155        )
 156
 157    def deserialize_searched_user(
 158        self, payload: typedefs.JSONObject
 159    ) -> user.SearchableDestinyUser:
 160        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
 161        if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown(
 162            raw_name
 163        ):
 164            name = raw_name
 165
 166        code: typing.Optional[int] = None
 167        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
 168            code = int(raw_code)
 169
 170        bungie_id: typing.Optional[int] = None
 171        if raw_bungie_id := payload.get("bungieNetMembershipId"):
 172            bungie_id = int(raw_bungie_id)
 173
 174        return user.SearchableDestinyUser(
 175            name=name,
 176            code=code,
 177            bungie_id=bungie_id,
 178            memberships=self.deserialize_destiny_memberships(
 179                payload["destinyMemberships"]
 180            ),
 181        )
 182
 183    def deserialize_user_credentials(
 184        self, payload: typedefs.JSONArray
 185    ) -> collections.Sequence[user.UserCredentials]:
 186        return [
 187            user.UserCredentials(
 188                type=enums.CredentialType(int(creds["credentialType"])),
 189                display_name=creds["credentialDisplayName"],
 190                is_public=creds["isPublic"],
 191                self_as_string=creds.get("credentialAsString", undefined.UNDEFINED),
 192            )
 193            for creds in payload
 194        ]
 195
 196    def deserialize_user_themes(
 197        self, payload: typedefs.JSONArray
 198    ) -> collections.Sequence[user.UserThemes]:
 199        return [
 200            user.UserThemes(
 201                id=int(entry["userThemeId"]),
 202                name=entry["userThemeName"]
 203                if "userThemeName" in entry
 204                else undefined.UNDEFINED,
 205                description=entry["userThemeDescription"]
 206                if "userThemeDescription" in entry
 207                else undefined.UNDEFINED,
 208            )
 209            for entry in payload
 210        ]
 211
 212    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
 213        # This is kinda redundant
 214        data = payload
 215
 216        # This is always outside the details.
 217        current_user_map: typing.Optional[
 218            collections.Mapping[str, clans.ClanMember]
 219        ] = None
 220        if raw_current_user_map := payload.get("currentUserMemberMap"):
 221            current_user_map = {
 222                membership_type: self.deserialize_clan_member(membership)
 223                for membership_type, membership in raw_current_user_map.items()
 224            }
 225
 226        try:
 227            data = payload["detail"]
 228        except KeyError:
 229            pass
 230
 231        id = data["groupId"]
 232        name = data["name"]
 233        created_at = data["creationDate"]
 234        member_count = data["memberCount"]
 235        about = data["about"]
 236        motto = data["motto"]
 237        is_public = data["isPublic"]
 238        banner = assets.Image(str(data["bannerPath"]))
 239        avatar = assets.Image(str(data["avatarPath"]))
 240        tags = data["tags"]
 241        type = data["groupType"]
 242
 243        features = data["features"]
 244        features_obj = clans.ClanFeatures(
 245            max_members=features["maximumMembers"],
 246            max_membership_types=features["maximumMembershipsOfGroupType"],
 247            capabilities=features["capabilities"],
 248            membership_types=features["membershipTypes"],
 249            invite_permissions=features["invitePermissionOverride"],
 250            update_banner_permissions=features["updateBannerPermissionOverride"],
 251            update_culture_permissions=features["updateCulturePermissionOverride"],
 252            join_level=features["joinLevel"],
 253        )
 254
 255        information: typedefs.JSONObject = data["clanInfo"]
 256        progression: collections.Mapping[int, progressions.Progression] = {
 257            int(prog_hash): self.deserialize_progressions(prog)
 258            for prog_hash, prog in information["d2ClanProgressions"].items()
 259        }
 260
 261        founder: typedefs.NoneOr[clans.ClanMember] = None
 262        if raw_founder := payload.get("founder"):
 263            founder = self.deserialize_clan_member(raw_founder)
 264
 265        return clans.Clan(
 266            net=self._net,
 267            id=int(id),
 268            name=name,
 269            type=enums.GroupType(type),
 270            created_at=time.clean_date(created_at),
 271            member_count=member_count,
 272            motto=motto,
 273            about=about,
 274            is_public=is_public,
 275            banner=banner,
 276            avatar=avatar,
 277            tags=tags,
 278            features=features_obj,
 279            owner=founder,
 280            progressions=progression,
 281            call_sign=information["clanCallsign"],
 282            banner_data=information["clanBannerData"],
 283            chat_security=data["chatSecurity"],
 284            conversation_id=int(data["conversationId"]),
 285            allow_chat=data["allowChat"],
 286            theme=data["theme"],
 287            current_user_membership=current_user_map,
 288        )
 289
 290    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
 291        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
 292        return clans.ClanMember(
 293            net=self._net,
 294            last_seen_name=destiny_user.last_seen_name,
 295            id=destiny_user.id,
 296            name=destiny_user.name,
 297            icon=destiny_user.icon,
 298            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
 299            group_id=int(data["groupId"]),
 300            joined_at=time.clean_date(data["joinDate"]),
 301            types=destiny_user.types,
 302            is_public=destiny_user.is_public,
 303            type=destiny_user.type,
 304            code=destiny_user.code,
 305            is_online=data["isOnline"],
 306            crossave_override=destiny_user.crossave_override,
 307            bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
 308            if "bungieNetUserInfo" in data
 309            else None,
 310            member_type=enums.ClanMemberType(int(data["memberType"])),
 311        )
 312
 313    def deserialize_clan_members(
 314        self, data: typedefs.JSONObject, /
 315    ) -> iterators.Iterator[clans.ClanMember]:
 316        return iterators.Iterator(
 317            [self.deserialize_clan_member(member) for member in data["results"]]
 318        )
 319
 320    def deserialize_group_member(
 321        self, payload: typedefs.JSONObject
 322    ) -> clans.GroupMember:
 323        member = payload["member"]
 324        return clans.GroupMember(
 325            net=self._net,
 326            join_date=time.clean_date(member["joinDate"]),
 327            group_id=int(member["groupId"]),
 328            member_type=enums.ClanMemberType(member["memberType"]),
 329            is_online=member["isOnline"],
 330            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
 331            inactive_memberships=payload.get("areAllMembershipsInactive", None),
 332            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
 333            group=self.deserialize_clan(payload["group"]),
 334        )
 335
 336    def _deserialize_clan_conversation(
 337        self, payload: typedefs.JSONObject
 338    ) -> clans.ClanConversation:
 339        return clans.ClanConversation(
 340            net=self._net,
 341            id=int(payload["conversationId"]),
 342            group_id=int(payload["groupId"]),
 343            name=(
 344                payload["chatName"]
 345                if not typedefs.is_unknown(payload["chatName"])
 346                else undefined.UNDEFINED
 347            ),
 348            chat_enabled=payload["chatEnabled"],
 349            security=payload["chatSecurity"],
 350        )
 351
 352    def deserialize_clan_conversations(
 353        self, payload: typedefs.JSONArray
 354    ) -> collections.Sequence[clans.ClanConversation]:
 355        return [self._deserialize_clan_conversation(conv) for conv in payload]
 356
 357    def deserialize_app_owner(
 358        self, payload: typedefs.JSONObject
 359    ) -> application.ApplicationOwner:
 360        return application.ApplicationOwner(
 361            net=self._net,
 362            name=payload.get("bungieGlobalDisplayName", undefined.UNDEFINED),
 363            id=int(payload["membershipId"]),
 364            type=enums.MembershipType(payload["membershipType"]),
 365            icon=assets.Image(str(payload["iconPath"])),
 366            is_public=payload["isPublic"],
 367            code=payload.get("bungieGlobalDisplayNameCode", None),
 368        )
 369
 370    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
 371        return application.Application(
 372            id=int(payload["applicationId"]),
 373            name=payload["name"],
 374            link=payload["link"],
 375            status=payload["status"],
 376            redirect_url=payload.get("redirectUrl", None),
 377            created_at=time.clean_date(str(payload["creationDate"])),
 378            published_at=time.clean_date(str(payload["firstPublished"])),
 379            owner=self.deserialize_app_owner(payload["team"][0]["user"]),  # type: ignore
 380            scope=payload.get("scope", undefined.UNDEFINED),
 381        )
 382
 383    def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character:
 384        total_time = time.format_played(int(payload["minutesPlayedTotal"]), suffix=True)
 385        return character.Character(
 386            net=self._net,
 387            id=int(payload["characterId"]),
 388            gender=enums.Gender(payload["genderType"]),
 389            race=enums.Race(payload["raceType"]),
 390            class_type=enums.Class(payload["classType"]),
 391            emblem=assets.Image(str(payload["emblemBackgroundPath"])),
 392            emblem_icon=assets.Image(str(payload["emblemPath"])),
 393            emblem_hash=int(payload["emblemHash"]),
 394            last_played=time.clean_date(payload["dateLastPlayed"]),
 395            total_played_time=total_time,
 396            member_id=int(payload["membershipId"]),
 397            member_type=enums.MembershipType(payload["membershipType"]),
 398            level=payload["baseCharacterLevel"],
 399            title_hash=payload.get("titleRecordHash", None),
 400            light=payload["light"],
 401            stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()},
 402        )
 403
 404    def deserialize_profile(
 405        self, payload: typedefs.JSONObject, /
 406    ) -> typing.Optional[profile.Profile]:
 407        if (raw_profile := payload.get("data")) is None:
 408            return None
 409
 410        payload = raw_profile
 411        id = int(payload["userInfo"]["membershipId"])
 412        name = payload["userInfo"]["displayName"]
 413        is_public = payload["userInfo"]["isPublic"]
 414        type = enums.MembershipType(payload["userInfo"]["membershipType"])
 415        last_played = time.clean_date(str(payload["dateLastPlayed"]))
 416        character_ids = [int(cid) for cid in payload["characterIds"]]
 417        power_cap = payload["currentSeasonRewardPowerCap"]
 418
 419        return profile.Profile(
 420            id=int(id),
 421            name=name,
 422            is_public=is_public,
 423            type=type,
 424            last_played=last_played,
 425            character_ids=character_ids,
 426            power_cap=power_cap,
 427            net=self._net,
 428        )
 429
 430    def deserialize_profile_item(
 431        self, payload: typedefs.JSONObject
 432    ) -> profile.ProfileItemImpl:
 433        instance_id: typing.Optional[int] = None
 434        if raw_instance_id := payload.get("itemInstanceId"):
 435            instance_id = int(raw_instance_id)
 436
 437        version_number: typing.Optional[int] = None
 438        if raw_version := payload.get("versionNumber"):
 439            version_number = int(raw_version)
 440
 441        transfer_status = enums.TransferStatus(payload["transferStatus"])
 442
 443        return profile.ProfileItemImpl(
 444            net=self._net,
 445            hash=payload["itemHash"],
 446            quantity=payload["quantity"],
 447            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
 448            location=enums.ItemLocation(payload["location"]),
 449            bucket=payload["bucketHash"],
 450            transfer_status=transfer_status,
 451            lockable=payload["lockable"],
 452            state=enums.ItemState(payload["state"]),
 453            dismantel_permissions=payload["dismantlePermission"],
 454            is_wrapper=payload["isWrapper"],
 455            instance_id=instance_id,
 456            version_number=version_number,
 457            ornament_id=payload.get("overrideStyleItemHash"),
 458        )
 459
 460    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
 461        return records.Objective(
 462            net=self._net,
 463            hash=payload["objectiveHash"],
 464            visible=payload["visible"],
 465            complete=payload["complete"],
 466            completion_value=payload["completionValue"],
 467            progress=payload.get("progress"),
 468            destination_hash=payload.get("destinationHash"),
 469            activity_hash=payload.get("activityHash"),
 470        )
 471
 472    def deserialize_records(
 473        self,
 474        payload: typedefs.JSONObject,
 475        scores: typing.Optional[records.RecordScores] = None,
 476        **nodes: int,
 477    ) -> records.Record:
 478        objectives: typing.Optional[list[records.Objective]] = None
 479        interval_objectives: typing.Optional[list[records.Objective]] = None
 480        record_state: typedefs.IntAnd[records.RecordState]
 481
 482        record_state = records.RecordState(payload["state"])
 483
 484        if raw_objs := payload.get("objectives"):
 485            objectives = [self.deserialize_objectives(obj) for obj in raw_objs]
 486
 487        if raw_interval_objs := payload.get("intervalObjectives"):
 488            interval_objectives = [
 489                self.deserialize_objectives(obj) for obj in raw_interval_objs
 490            ]
 491
 492        return records.Record(
 493            scores=scores,
 494            categories_node_hash=nodes.get("categories_hash", undefined.UNDEFINED),
 495            seals_node_hash=nodes.get("seals_hash", undefined.UNDEFINED),
 496            state=record_state,
 497            objectives=objectives,
 498            interval_objectives=interval_objectives,
 499            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 500            completion_times=payload.get("completedCount", None),
 501            reward_visibility=payload.get("rewardVisibilty", None),
 502        )
 503
 504    def deserialize_character_records(
 505        self,
 506        payload: typedefs.JSONObject,
 507        scores: typing.Optional[records.RecordScores] = None,
 508        record_hashes: typing.Optional[list[int]] = None,
 509    ) -> records.CharacterRecord:
 510        record = self.deserialize_records(payload, scores)
 511        return records.CharacterRecord(
 512            scores=scores,
 513            categories_node_hash=record.categories_node_hash,
 514            seals_node_hash=record.seals_node_hash,
 515            state=record.state,
 516            objectives=record.objectives,
 517            interval_objectives=record.interval_objectives,
 518            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 519            completion_times=payload.get("completedCount"),
 520            reward_visibility=payload.get("rewardVisibilty"),
 521            record_hashes=record_hashes or [],
 522        )
 523
 524    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
 525        return character.Dye(
 526            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
 527        )
 528
 529    def deserialize_character_customization(
 530        self, payload: typedefs.JSONObject
 531    ) -> character.CustomizationOptions:
 532        return character.CustomizationOptions(
 533            personality=payload["personality"],
 534            face=payload["face"],
 535            skin_color=payload["skinColor"],
 536            lip_color=payload["lipColor"],
 537            eye_color=payload["eyeColor"],
 538            hair_colors=payload.get("hairColors", []),
 539            feature_colors=payload.get("featureColors", []),
 540            decal_color=payload["decalColor"],
 541            wear_helmet=payload["wearHelmet"],
 542            hair_index=payload["hairIndex"],
 543            feature_index=payload["featureIndex"],
 544            decal_index=payload["decalIndex"],
 545        )
 546
 547    def deserialize_character_minimal_equipments(
 548        self, payload: typedefs.JSONObject
 549    ) -> character.MinimalEquipments:
 550        dyes = None
 551        if raw_dyes := payload.get("dyes"):
 552            if raw_dyes:
 553                dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes]
 554        return character.MinimalEquipments(
 555            net=self._net, item_hash=payload["itemHash"], dyes=dyes
 556        )
 557
 558    def deserialize_character_render_data(
 559        self, payload: typedefs.JSONObject, /
 560    ) -> character.RenderedData:
 561        return character.RenderedData(
 562            net=self._net,
 563            customization=self.deserialize_character_customization(
 564                payload["customization"]
 565            ),
 566            custom_dyes=[
 567                self.deserialize_character_dye(dye)
 568                for dye in payload["customDyes"]
 569                if dye
 570            ],
 571            equipment=[
 572                self.deserialize_character_minimal_equipments(equipment)
 573                for equipment in payload["peerView"]["equipment"]
 574            ],
 575        )
 576
 577    def deserialize_available_activity(
 578        self, payload: typedefs.JSONObject
 579    ) -> activity.AvailableActivity:
 580        return activity.AvailableActivity(
 581            hash=payload["activityHash"],
 582            is_new=payload["isNew"],
 583            is_completed=payload["isCompleted"],
 584            is_visible=payload["isVisible"],
 585            display_level=payload.get("displayLevel"),
 586            recommended_light=payload.get("recommendedLight"),
 587            difficulty=activity.Difficulty(payload["difficultyTier"]),
 588            can_join=payload["canJoin"],
 589            can_lead=payload["canLead"],
 590        )
 591
 592    def deserialize_character_activity(
 593        self, payload: typedefs.JSONObject
 594    ) -> activity.CharacterActivity:
 595        current_mode: typing.Optional[enums.GameMode] = None
 596        if raw_current_mode := payload.get("currentActivityModeType"):
 597            current_mode = enums.GameMode(raw_current_mode)
 598
 599        current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None
 600        if raw_current_modes := payload.get("currentActivityModeTypes"):
 601            current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes]
 602
 603        return activity.CharacterActivity(
 604            date_started=time.clean_date(payload["dateActivityStarted"]),
 605            current_hash=payload["currentActivityHash"],
 606            current_mode_hash=payload["currentActivityModeHash"],
 607            current_mode=current_mode,
 608            current_mode_hashes=payload.get("currentActivityModeHashes"),
 609            current_mode_types=current_mode_types,
 610            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
 611            last_story_hash=payload["lastCompletedStoryHash"],
 612            available_activities=[
 613                self.deserialize_available_activity(activity_)
 614                for activity_ in payload["availableActivities"]
 615            ],
 616        )
 617
 618    def deserialize_profile_items(
 619        self, payload: typedefs.JSONObject, /
 620    ) -> list[profile.ProfileItemImpl]:
 621        return [self.deserialize_profile_item(item) for item in payload["items"]]
 622
 623    def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node:
 624        return records.Node(
 625            state=int(payload["state"]),
 626            objective=self.deserialize_objectives(payload["objective"])
 627            if "objective" in payload
 628            else None,
 629            progress_value=int(payload["progressValue"]),
 630            completion_value=int(payload["completionValue"]),
 631            record_category_score=int(payload["recordCategoryScore"])
 632            if "recordCategoryScore" in payload
 633            else None,
 634        )
 635
 636    @staticmethod
 637    def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible:
 638        recent_collectibles: typing.Optional[collections.Collection[int]] = None
 639        if raw_recent_collectibles := payload.get("recentCollectibleHashes"):
 640            recent_collectibles = [
 641                int(item_hash) for item_hash in raw_recent_collectibles
 642            ]
 643
 644        collectibles: dict[int, int] = {}
 645        for item_hash, mapping in payload["collectibles"].items():
 646            collectibles[int(item_hash)] = int(mapping["state"])
 647
 648        return items.Collectible(
 649            recent_collectibles=recent_collectibles,
 650            collectibles=collectibles,
 651            collection_categorie_hash=int(payload["collectionCategoriesRootNodeHash"]),
 652            collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]),
 653        )
 654
 655    @staticmethod
 656    def _deserialize_currencies(
 657        payload: typedefs.JSONObject,
 658    ) -> collections.Sequence[items.Currency]:
 659        return [
 660            items.Currency(hash=int(item_hash), amount=int(amount))
 661            for item_hash, amount in payload["itemQuantities"].items()
 662        ]
 663
 664    def deserialize_progressions(
 665        self, payload: typedefs.JSONObject
 666    ) -> progressions.Progression:
 667        return progressions.Progression(
 668            hash=int(payload["progressionHash"]),
 669            level=int(payload["level"]),
 670            cap=int(payload["levelCap"]),
 671            daily_limit=int(payload["dailyLimit"]),
 672            weekly_limit=int(payload["weeklyLimit"]),
 673            current_progress=int(payload["currentProgress"]),
 674            daily_progress=int(payload["dailyProgress"]),
 675            needed=int(payload["progressToNextLevel"]),
 676            next_level=int(payload["nextLevelAt"]),
 677        )
 678
 679    def _deserialize_factions(
 680        self, payload: typedefs.JSONObject
 681    ) -> progressions.Factions:
 682        progs = self.deserialize_progressions(payload)
 683        return progressions.Factions(
 684            hash=progs.hash,
 685            level=progs.level,
 686            cap=progs.cap,
 687            daily_limit=progs.daily_limit,
 688            weekly_limit=progs.weekly_limit,
 689            current_progress=progs.current_progress,
 690            daily_progress=progs.daily_progress,
 691            needed=progs.needed,
 692            next_level=progs.next_level,
 693            faction_hash=payload["factionHash"],
 694            faction_vendor_hash=payload["factionVendorIndex"],
 695        )
 696
 697    def _deserialize_milestone_available_quest(
 698        self, payload: typedefs.JSONObject
 699    ) -> milestones.MilestoneQuest:
 700        return milestones.MilestoneQuest(
 701            item_hash=payload["questItemHash"],
 702            status=self._deserialize_milestone_quest_status(payload["status"]),
 703        )
 704
 705    def _deserialize_milestone_activity(
 706        self, payload: typedefs.JSONObject
 707    ) -> milestones.MilestoneActivity:
 708        phases: typing.Optional[
 709            collections.Sequence[milestones.MilestoneActivityPhase]
 710        ] = None
 711        if raw_phases := payload.get("phases"):
 712            phases = [
 713                milestones.MilestoneActivityPhase(
 714                    is_completed=obj["complete"], hash=obj["phaseHash"]
 715                )
 716                for obj in raw_phases
 717            ]
 718
 719        return milestones.MilestoneActivity(
 720            hash=payload["activityHash"],
 721            challenges=[
 722                self.deserialize_objectives(obj["objective"])
 723                for obj in payload["challenges"]
 724            ],
 725            modifier_hashes=payload.get("modifierHashes"),
 726            boolean_options=payload.get("booleanActivityOptions"),
 727            phases=phases,
 728        )
 729
 730    def _deserialize_milestone_quest_status(
 731        self, payload: typedefs.JSONObject
 732    ) -> milestones.QuestStatus:
 733        return milestones.QuestStatus(
 734            net=self._net,
 735            quest_hash=payload["questHash"],
 736            step_hash=payload["stepHash"],
 737            step_objectives=[
 738                self.deserialize_objectives(objective)
 739                for objective in payload["stepObjectives"]
 740            ],
 741            is_tracked=payload["tracked"],
 742            is_completed=payload["completed"],
 743            started=payload["started"],
 744            item_instance_id=payload["itemInstanceId"],
 745            vendor_hash=payload.get("vendorHash"),
 746            is_redeemed=payload["redeemed"],
 747        )
 748
 749    def _deserialize_milestone_rewards(
 750        self, payload: typedefs.JSONObject
 751    ) -> milestones.MilestoneReward:
 752        return milestones.MilestoneReward(
 753            category_hash=payload["rewardCategoryHash"],
 754            entries=[
 755                milestones.MilestoneRewardEntry(
 756                    entry_hash=entry["rewardEntryHash"],
 757                    is_earned=entry["earned"],
 758                    is_redeemed=entry["redeemed"],
 759                )
 760                for entry in payload["entries"]
 761            ],
 762        )
 763
 764    def deserialize_milestone(
 765        self, payload: typedefs.JSONObject
 766    ) -> milestones.Milestone:
 767        start_date: typing.Optional[datetime.datetime] = None
 768        if raw_start_date := payload.get("startDate"):
 769            start_date = time.clean_date(raw_start_date)
 770
 771        end_date: typing.Optional[datetime.datetime] = None
 772        if raw_end_date := payload.get("endDate"):
 773            end_date = time.clean_date(raw_end_date)
 774
 775        rewards: typing.Optional[
 776            collections.Collection[milestones.MilestoneReward]
 777        ] = None
 778        if raw_rewards := payload.get("rewards"):
 779            rewards = [
 780                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
 781            ]
 782
 783        activities: typing.Optional[
 784            collections.Sequence[milestones.MilestoneActivity]
 785        ] = None
 786        if raw_activities := payload.get("activities"):
 787            activities = [
 788                self._deserialize_milestone_activity(active)
 789                for active in raw_activities
 790            ]
 791
 792        quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None
 793        if raw_quests := payload.get("availableQuests"):
 794            quests = [
 795                self._deserialize_milestone_available_quest(quest)
 796                for quest in raw_quests
 797            ]
 798
 799        vendors: typing.Optional[
 800            collections.Sequence[milestones.MilestoneVendor]
 801        ] = None
 802        if raw_vendors := payload.get("vendors"):
 803            vendors = [
 804                milestones.MilestoneVendor(
 805                    vendor_hash=vendor["vendorHash"],
 806                    preview_itemhash=vendor.get("previewItemHash"),
 807                )
 808                for vendor in raw_vendors
 809            ]
 810
 811        return milestones.Milestone(
 812            hash=payload["milestoneHash"],
 813            start_date=start_date,
 814            end_date=end_date,
 815            order=payload["order"],
 816            rewards=rewards,
 817            available_quests=quests,
 818            activities=activities,
 819            vendors=vendors,
 820        )
 821
 822    def _deserialize_artifact_tiers(
 823        self, payload: typedefs.JSONObject
 824    ) -> season.ArtifactTier:
 825        return season.ArtifactTier(
 826            hash=payload["tierHash"],
 827            is_unlocked=payload["isUnlocked"],
 828            points_to_unlock=payload["pointsToUnlock"],
 829            items=[
 830                season.ArtifactTierItem(
 831                    hash=item["itemHash"], is_active=item["isActive"]
 832                )
 833                for item in payload["items"]
 834            ],
 835        )
 836
 837    def deserialize_characters(
 838        self, payload: typedefs.JSONObject
 839    ) -> collections.Mapping[int, character.Character]:
 840        return {
 841            int(char_id): self._set_character_attrs(char)
 842            for char_id, char in payload["data"].items()
 843        }
 844
 845    def deserialize_character(
 846        self, payload: typedefs.JSONObject
 847    ) -> character.Character:
 848        return self._set_character_attrs(payload)
 849
 850    def deserialize_character_equipments(
 851        self, payload: typedefs.JSONObject
 852    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
 853        return {
 854            int(char_id): self.deserialize_profile_items(item)
 855            for char_id, item in payload["data"].items()
 856        }
 857
 858    def deserialize_character_activities(
 859        self, payload: typedefs.JSONObject
 860    ) -> collections.Mapping[int, activity.CharacterActivity]:
 861        return {
 862            int(char_id): self.deserialize_character_activity(data)
 863            for char_id, data in payload["data"].items()
 864        }
 865
 866    def deserialize_characters_render_data(
 867        self, payload: typedefs.JSONObject
 868    ) -> collections.Mapping[int, character.RenderedData]:
 869        return {
 870            int(char_id): self.deserialize_character_render_data(data)
 871            for char_id, data in payload["data"].items()
 872        }
 873
 874    def deserialize_character_progressions(
 875        self, payload: typedefs.JSONObject
 876    ) -> character.CharacterProgression:
 877        progressions_ = {
 878            int(prog_id): self.deserialize_progressions(prog)
 879            for prog_id, prog in payload["progressions"].items()
 880        }
 881
 882        factions = {
 883            int(faction_id): self._deserialize_factions(faction)
 884            for faction_id, faction in payload["factions"].items()
 885        }
 886
 887        milestones_ = {
 888            int(milestone_hash): self.deserialize_milestone(milestone)
 889            for milestone_hash, milestone in payload["milestones"].items()
 890        }
 891
 892        uninstanced_item_objectives = {
 893            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
 894            for item_hash, obj in payload["uninstancedItemObjectives"].items()
 895        }
 896
 897        artifact = payload["seasonalArtifact"]
 898        seasonal_artifact = season.CharacterScopedArtifact(
 899            hash=artifact["artifactHash"],
 900            points_used=artifact["pointsUsed"],
 901            reset_count=artifact["resetCount"],
 902            tiers=[
 903                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
 904            ],
 905        )
 906        checklists = payload["checklists"]
 907
 908        return character.CharacterProgression(
 909            progressions=progressions_,
 910            factions=factions,
 911            checklists=checklists,
 912            milestones=milestones_,
 913            seasonal_artifact=seasonal_artifact,
 914            uninstanced_item_objectives=uninstanced_item_objectives,
 915        )
 916
 917    def deserialize_character_progressions_mapping(
 918        self, payload: typedefs.JSONObject
 919    ) -> collections.Mapping[int, character.CharacterProgression]:
 920        character_progressions: collections.Mapping[
 921            int, character.CharacterProgression
 922        ] = {}
 923        for char_id, data in payload["data"].items():
 924            # A little hack to stop mypy complaining about Mapping <-> dict
 925            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)  # type: ignore[index]
 926        return character_progressions
 927
 928    def deserialize_characters_records(
 929        self,
 930        payload: typedefs.JSONObject,
 931    ) -> collections.Mapping[int, records.CharacterRecord]:
 932        return {
 933            int(rec_id): self.deserialize_character_records(
 934                rec, record_hashes=payload.get("featuredRecordHashes")
 935            )
 936            for rec_id, rec in payload["records"].items()
 937        }
 938
 939    def deserialize_profile_records(
 940        self, payload: typedefs.JSONObject
 941    ) -> collections.Mapping[int, records.Record]:
 942        raw_profile_records = payload["data"]
 943        scores = records.RecordScores(
 944            current_score=raw_profile_records["score"],
 945            legacy_score=raw_profile_records["legacyScore"],
 946            lifetime_score=raw_profile_records["lifetimeScore"],
 947        )
 948        return {
 949            int(record_id): self.deserialize_records(
 950                record,
 951                scores,
 952                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
 953                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
 954            )
 955            for record_id, record in raw_profile_records["records"].items()
 956        }
 957
 958    def _deserialize_craftable_socket_plug(
 959        self, payload: typedefs.JSONObject
 960    ) -> items.CraftableSocketPlug:
 961        return items.CraftableSocketPlug(
 962            item_hash=int(payload["plugItemHash"]),
 963            failed_requirement_indexes=payload.get("failedRequirementIndexes", []),
 964        )
 965
 966    def _deserialize_craftable_socket(
 967        self, payload: typedefs.JSONObject
 968    ) -> items.CraftableSocket:
 969        plugs: list[items.CraftableSocketPlug] = []
 970        if raw_plug := payload.get("plug"):
 971            plugs.extend(
 972                self._deserialize_craftable_socket_plug(plug) for plug in raw_plug
 973            )
 974
 975        return items.CraftableSocket(
 976            plug_set_hash=int(payload["plugSetHash"]), plugs=plugs
 977        )
 978
 979    def _deserialize_craftable_item(
 980        self, payload: typedefs.JSONObject
 981    ) -> items.CraftableItem:
 982        return items.CraftableItem(
 983            is_visible=payload["visible"],
 984            failed_requirement_indexes=payload.get("failedRequirementIndexes", []),
 985            sockets=[
 986                self._deserialize_craftable_socket(socket)
 987                for socket in payload["sockets"]
 988            ],
 989        )
 990
 991    def deserialize_craftables_component(
 992        self, payload: typedefs.JSONObject
 993    ) -> components.CraftablesComponent:
 994        return components.CraftablesComponent(
 995            net=self._net,
 996            craftables={
 997                int(item_id): self._deserialize_craftable_item(item)
 998                for item_id, item in payload["craftables"].items()
 999                if item is not None
1000            },
1001            crafting_root_node_hash=payload["craftingRootNodeHash"],
1002        )
1003
1004    def deserialize_components(  # noqa: C901 Too complex.
1005        self, payload: typedefs.JSONObject
1006    ) -> components.Component:
1007        profile_: typing.Optional[profile.Profile] = None
1008        if raw_profile := payload.get("profile"):
1009            profile_ = self.deserialize_profile(raw_profile)
1010
1011        profile_progression: typing.Optional[profile.ProfileProgression] = None
1012        if raw_profile_progression := payload.get("profileProgression"):
1013            profile_progression = self.deserialize_profile_progression(
1014                raw_profile_progression
1015            )
1016
1017        profile_currencies: typing.Optional[
1018            collections.Sequence[profile.ProfileItemImpl]
1019        ] = None
1020        if raw_profile_currencies := payload.get("profileCurrencies"):
1021            if "data" in raw_profile_currencies:
1022                profile_currencies = self.deserialize_profile_items(
1023                    raw_profile_currencies["data"]
1024                )
1025
1026        profile_inventories: typing.Optional[
1027            collections.Sequence[profile.ProfileItemImpl]
1028        ] = None
1029        if raw_profile_inventories := payload.get("profileInventory"):
1030            if "data" in raw_profile_inventories:
1031                profile_inventories = self.deserialize_profile_items(
1032                    raw_profile_inventories["data"]
1033                )
1034
1035        profile_records: typing.Optional[
1036            collections.Mapping[int, records.Record]
1037        ] = None
1038
1039        if raw_profile_records_ := payload.get("profileRecords"):
1040            profile_records = self.deserialize_profile_records(raw_profile_records_)
1041
1042        characters: typing.Optional[typing.Mapping[int, character.Character]] = None
1043        if raw_characters := payload.get("characters"):
1044            characters = self.deserialize_characters(raw_characters)
1045
1046        character_records: typing.Optional[
1047            collections.Mapping[int, records.CharacterRecord]
1048        ] = None
1049
1050        if raw_character_records := payload.get("characterRecords"):
1051            # Had to do it in two steps..
1052            to_update: typedefs.JSONObject = {}
1053            for _, data in raw_character_records["data"].items():
1054                for record_id, record in data.items():
1055                    to_update[record_id] = record
1056
1057            character_records = {
1058                int(rec_id): self.deserialize_character_records(
1059                    rec, record_hashes=to_update.get("featuredRecordHashes")
1060                )
1061                for rec_id, rec in to_update["records"].items()
1062            }
1063
1064        character_equipments: typing.Optional[
1065            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1066        ] = None
1067        if raw_character_equips := payload.get("characterEquipment"):
1068            character_equipments = self.deserialize_character_equipments(
1069                raw_character_equips
1070            )
1071
1072        character_inventories: typing.Optional[
1073            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1074        ] = None
1075        if raw_character_inventories := payload.get("characterInventories"):
1076            if "data" in raw_character_inventories:
1077                character_inventories = self.deserialize_character_equipments(
1078                    raw_character_inventories
1079                )
1080
1081        character_activities: typing.Optional[
1082            collections.Mapping[int, activity.CharacterActivity]
1083        ] = None
1084        if raw_char_acts := payload.get("characterActivities"):
1085            character_activities = self.deserialize_character_activities(raw_char_acts)
1086
1087        character_render_data: typing.Optional[
1088            collections.Mapping[int, character.RenderedData]
1089        ] = None
1090        if raw_character_render_data := payload.get("characterRenderData"):
1091            character_render_data = self.deserialize_characters_render_data(
1092                raw_character_render_data
1093            )
1094
1095        character_progressions: typing.Optional[
1096            collections.Mapping[int, character.CharacterProgression]
1097        ] = None
1098
1099        if raw_character_progressions := payload.get("characterProgressions"):
1100            character_progressions = self.deserialize_character_progressions_mapping(
1101                raw_character_progressions
1102            )
1103
1104        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1105        if raw_profile_string_vars := payload.get("profileStringVariables"):
1106            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1107
1108        character_string_vars: typing.Optional[
1109            collections.Mapping[int, collections.Mapping[int, int]]
1110        ] = None
1111        if raw_character_string_vars := payload.get("characterStringVariables"):
1112            character_string_vars = {
1113                int(char_id): data["integerValuesByHash"]
1114                for char_id, data in raw_character_string_vars["data"].items()
1115            }
1116
1117        metrics: typing.Optional[
1118            collections.Sequence[
1119                collections.Mapping[
1120                    int, tuple[bool, typing.Optional[records.Objective]]
1121                ]
1122            ]
1123        ] = None
1124        root_node_hash: typing.Optional[int] = None
1125
1126        if raw_metrics := payload.get("metrics"):
1127            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1128            metrics = [
1129                {
1130                    int(metrics_hash): (
1131                        data["invisible"],
1132                        self.deserialize_objectives(data["objectiveProgress"])
1133                        if "objectiveProgress" in data
1134                        else None,
1135                    )
1136                    for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1137                }
1138            ]
1139        transitory: typing.Optional[fireteams.FireteamParty] = None
1140        if raw_transitory := payload.get("profileTransitoryData"):
1141            if "data" in raw_transitory:
1142                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1143
1144        item_components: typing.Optional[components.ItemsComponent] = None
1145        if raw_item_components := payload.get("itemComponents"):
1146            item_components = self.deserialize_items_component(raw_item_components)
1147
1148        profile_plugsets: typing.Optional[
1149            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1150        ] = None
1151
1152        if raw_profile_plugs := payload.get("profilePlugSets"):
1153            profile_plugsets = {
1154                int(index): [self.deserialize_plug_item_state(state) for state in data]
1155                for index, data in raw_profile_plugs["data"]["plugs"].items()
1156            }
1157
1158        character_plugsets: typing.Optional[
1159            collections.Mapping[
1160                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1161            ]
1162        ] = None
1163        if raw_char_plugsets := payload.get("characterPlugSets"):
1164            character_plugsets = {
1165                int(char_id): {
1166                    int(index): [
1167                        self.deserialize_plug_item_state(state) for state in data
1168                    ]
1169                    for index, data in inner["plugs"].items()
1170                }
1171                for char_id, inner in raw_char_plugsets["data"].items()
1172            }
1173
1174        character_collectibles: typing.Optional[
1175            collections.Mapping[int, items.Collectible]
1176        ] = None
1177        if raw_character_collectibles := payload.get("characterCollectibles"):
1178            character_collectibles = {
1179                int(char_id): self._deserialize_collectible(data)
1180                for char_id, data in raw_character_collectibles["data"].items()
1181            }
1182
1183        profile_collectibles: typing.Optional[items.Collectible] = None
1184        if raw_profile_collectibles := payload.get("profileCollectibles"):
1185            profile_collectibles = self._deserialize_collectible(
1186                raw_profile_collectibles["data"]
1187            )
1188
1189        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1190        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1191            profile_nodes = {
1192                int(node_hash): self._deserialize_node(node)
1193                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1194            }
1195
1196        character_nodes: typing.Optional[
1197            collections.Mapping[int, collections.Mapping[int, records.Node]]
1198        ] = None
1199        if raw_character_nodes := payload.get("characterPresentationNodes"):
1200            character_nodes = {
1201                int(char_id): {
1202                    int(node_hash): self._deserialize_node(node)
1203                    for node_hash, node in each_character["nodes"].items()
1204                }
1205                for char_id, each_character in raw_character_nodes["data"].items()
1206            }
1207
1208        platform_silver: typing.Optional[
1209            collections.Mapping[str, profile.ProfileItemImpl]
1210        ] = None
1211        if raw_platform_silver := payload.get("platformSilver"):
1212            if "data" in raw_platform_silver:
1213                platform_silver = {
1214                    platform_name: self.deserialize_profile_item(item)
1215                    for platform_name, item in raw_platform_silver["data"][
1216                        "platformSilver"
1217                    ].items()
1218                }
1219
1220        character_currency_lookups: typing.Optional[
1221            collections.Mapping[int, collections.Sequence[items.Currency]]
1222        ] = None
1223        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1224            if "data" in raw_char_lookups:
1225                character_currency_lookups = {
1226                    int(char_id): self._deserialize_currencies(currencie)
1227                    for char_id, currencie in raw_char_lookups["data"].items()
1228                }
1229
1230        character_craftables: typing.Optional[
1231            collections.Mapping[int, components.CraftablesComponent]
1232        ] = None
1233        if raw_character_craftables := payload.get("characterCraftables"):
1234            if "data" in raw_character_craftables:
1235                character_craftables = {
1236                    int(char_id): self.deserialize_craftables_component(craftable)
1237                    for char_id, craftable in raw_character_craftables["data"].items()
1238                }
1239
1240        return components.Component(
1241            profiles=profile_,
1242            profile_progression=profile_progression,
1243            profile_currencies=profile_currencies,
1244            profile_inventories=profile_inventories,
1245            profile_records=profile_records,
1246            characters=characters,
1247            character_records=character_records,
1248            character_equipments=character_equipments,
1249            character_inventories=character_inventories,
1250            character_activities=character_activities,
1251            character_render_data=character_render_data,
1252            character_progressions=character_progressions,
1253            profile_string_variables=profile_string_vars,
1254            character_string_variables=character_string_vars,
1255            metrics=metrics,
1256            root_node_hash=root_node_hash,
1257            transitory=transitory,
1258            item_components=item_components,
1259            profile_plugsets=profile_plugsets,
1260            character_plugsets=character_plugsets,
1261            character_collectibles=character_collectibles,
1262            profile_collectibles=profile_collectibles,
1263            profile_nodes=profile_nodes,
1264            character_nodes=character_nodes,
1265            platform_silver=platform_silver,
1266            character_currency_lookups=character_currency_lookups,
1267            character_craftables=character_craftables,
1268        )
1269
1270    def deserialize_items_component(
1271        self, payload: typedefs.JSONObject
1272    ) -> components.ItemsComponent:
1273        instances: typing.Optional[
1274            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1275        ] = None
1276        if raw_instances := payload.get("instances"):
1277            instances = [
1278                {
1279                    int(ins_id): self.deserialize_instanced_item(item)
1280                    for ins_id, item in raw_instances["data"].items()
1281                }
1282            ]
1283
1284        render_data: typing.Optional[
1285            collections.Mapping[int, tuple[bool, dict[int, int]]]
1286        ] = None
1287        if raw_render_data := payload.get("renderData"):
1288            render_data = {
1289                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1290                for ins_id, data in raw_render_data["data"].items()
1291            }
1292
1293        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1294        if raw_stats := payload.get("stats"):
1295            builder: collections.Mapping[int, items.ItemStatsView] = {}
1296            for ins_id, stat in raw_stats["data"].items():
1297                for _, items_ in stat.items():
1298                    builder[int(ins_id)] = self.deserialize_item_stats_view(items_)  # type: ignore[index]
1299            stats = builder
1300
1301        sockets: typing.Optional[
1302            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1303        ] = None
1304        if raw_sockets := payload.get("sockets"):
1305            sockets = {
1306                int(ins_id): [
1307                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1308                ]
1309                for ins_id, item in raw_sockets["data"].items()
1310            }
1311
1312        objeectives: typing.Optional[
1313            collections.Mapping[int, collections.Sequence[records.Objective]]
1314        ] = None
1315        if raw_objectives := payload.get("objectives"):
1316            objeectives = {
1317                int(ins_id): [self.deserialize_objectives(objective)]
1318                for ins_id, data in raw_objectives["data"].items()
1319                for objective in data["objectives"]
1320            }
1321
1322        perks: typing.Optional[
1323            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1324        ] = None
1325        if raw_perks := payload.get("perks"):
1326            perks = {
1327                int(ins_id): [
1328                    self.deserialize_item_perk(perk) for perk in item["perks"]
1329                ]
1330                for ins_id, item in raw_perks["data"].items()
1331            }
1332
1333        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1334        if raw_plug_states := payload.get("plugStates"):
1335            pending_states: list[items.PlugItemState] = []
1336            for _, plug in raw_plug_states["data"].items():
1337                pending_states.append(self.deserialize_plug_item_state(plug))
1338            plug_states = pending_states
1339
1340        reusable_plugs: typing.Optional[
1341            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1342        ] = None
1343        if raw_re_plugs := payload.get("reusablePlugs"):
1344            reusable_plugs = {
1345                int(ins_id): [
1346                    self.deserialize_plug_item_state(state) for state in inner
1347                ]
1348                for ins_id, plug in raw_re_plugs["data"].items()
1349                for inner in list(plug["plugs"].values())
1350            }
1351
1352        plug_objectives: typing.Optional[
1353            collections.Mapping[
1354                int, collections.Mapping[int, collections.Collection[records.Objective]]
1355            ]
1356        ] = None
1357        if raw_plug_objectives := payload.get("plugObjectives"):
1358            plug_objectives = {
1359                int(ins_id): {
1360                    int(obj_hash): [self.deserialize_objectives(obj) for obj in objs]
1361                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1362                }
1363                for ins_id, inner in raw_plug_objectives["data"].items()
1364            }
1365
1366        return components.ItemsComponent(
1367            sockets=sockets,
1368            stats=stats,
1369            render_data=render_data,
1370            instances=instances,
1371            objectives=objeectives,
1372            perks=perks,
1373            plug_states=plug_states,
1374            reusable_plugs=reusable_plugs,
1375            plug_objectives=plug_objectives,
1376        )
1377
1378    def deserialize_character_component(  # type: ignore[call-arg]
1379        self, payload: typedefs.JSONObject
1380    ) -> components.CharacterComponent:
1381        character_: typing.Optional[character.Character] = None
1382        if raw_singuler_character := payload.get("character"):
1383            character_ = self.deserialize_character(raw_singuler_character["data"])
1384
1385        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1386        if raw_inventory := payload.get("inventory"):
1387            if "data" in raw_inventory:
1388                inventory = self.deserialize_profile_items(raw_inventory["data"])
1389
1390        activities: typing.Optional[activity.CharacterActivity] = None
1391        if raw_activities := payload.get("activities"):
1392            activities = self.deserialize_character_activity(raw_activities["data"])
1393
1394        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1395        if raw_equipments := payload.get("equipment"):
1396            equipment = self.deserialize_profile_items(raw_equipments["data"])
1397
1398        progressions_: typing.Optional[character.CharacterProgression] = None
1399        if raw_progressions := payload.get("progressions"):
1400            progressions_ = self.deserialize_character_progressions(
1401                raw_progressions["data"]
1402            )
1403
1404        render_data: typing.Optional[character.RenderedData] = None
1405        if raw_render_data := payload.get("renderData"):
1406            render_data = self.deserialize_character_render_data(
1407                raw_render_data["data"]
1408            )
1409
1410        character_records: typing.Optional[
1411            collections.Mapping[int, records.CharacterRecord]
1412        ] = None
1413        if raw_char_records := payload.get("records"):
1414            character_records = self.deserialize_characters_records(
1415                raw_char_records["data"]
1416            )
1417
1418        item_components: typing.Optional[components.ItemsComponent] = None
1419        if raw_item_components := payload.get("itemComponents"):
1420            item_components = self.deserialize_items_component(raw_item_components)
1421
1422        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1423        if raw_nodes := payload.get("presentationNodes"):
1424            nodes = {
1425                int(node_hash): self._deserialize_node(node)
1426                for node_hash, node in raw_nodes["data"]["nodes"].items()
1427            }
1428
1429        collectibles: typing.Optional[items.Collectible] = None
1430        if raw_collectibles := payload.get("collectibles"):
1431            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1432
1433        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1434        if raw_currencies := payload.get("currencyLookups"):
1435            if "data" in raw_currencies:
1436                currency_lookups = self._deserialize_currencies(raw_currencies)
1437
1438        return components.CharacterComponent(
1439            activities=activities,
1440            equipment=equipment,
1441            inventory=inventory,
1442            progressions=progressions_,
1443            render_data=render_data,
1444            character=character_,
1445            character_records=character_records,
1446            profile_records=None,
1447            item_components=item_components,
1448            currency_lookups=currency_lookups,
1449            collectibles=collectibles,
1450            nodes=nodes,
1451        )
1452
1453    def _set_entity_attrs(
1454        self, payload: typedefs.JSONObject, *, key: str = "displayProperties"
1455    ) -> entity.Entity:
1456        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1457        description: undefined.UndefinedOr[str] = undefined.UNDEFINED
1458
1459        if properties := payload[key]:
1460            if (raw_name := properties["name"]) is not typedefs.Unknown:
1461                name = raw_name
1462
1463            if (
1464                raw_description := properties["description"]
1465            ) and not typedefs.is_unknown(raw_description):
1466                description = raw_description
1467
1468        return entity.Entity(
1469            net=self._net,
1470            hash=payload["hash"],
1471            index=payload["index"],
1472            name=name,
1473            description=description,
1474            has_icon=properties["hasIcon"],
1475            icon=assets.Image(properties["icon"] if "icon" in properties else None),
1476        )
1477
1478    def deserialize_inventory_results(
1479        self, payload: typedefs.JSONObject
1480    ) -> iterators.Iterator[entity.SearchableEntity]:
1481        suggested_words: list[str] = payload["suggestedWords"]
1482
1483        def _check_unknown(s: str) -> undefined.UndefinedOr[str]:
1484            return s if not typedefs.is_unknown(s) else undefined.UNDEFINED
1485
1486        return iterators.Iterator(
1487            [
1488                entity.SearchableEntity(
1489                    net=self._net,
1490                    hash=data["hash"],
1491                    entity_type=data["entityType"],
1492                    weight=data["weight"],
1493                    suggested_words=suggested_words,
1494                    name=data["displayProperties"]["name"],
1495                    has_icon=data["displayProperties"]["hasIcon"],
1496                    description=_check_unknown(
1497                        data["displayProperties"]["description"]
1498                    ),
1499                    icon=assets.Image(data["displayProperties"]["icon"]),
1500                )
1501                for data in payload["results"]["results"]
1502            ]
1503        )
1504
1505    def _deserialize_inventory_item_objects(
1506        self, payload: typedefs.JSONObject
1507    ) -> entity.InventoryEntityObjects:
1508        return entity.InventoryEntityObjects(
1509            action=payload.get("action"),
1510            set_data=payload.get("setData"),
1511            stats=payload.get("stats"),
1512            equipping_block=payload.get("equippingBlock"),
1513            translation_block=payload.get("translationBlock"),
1514            preview=payload.get("preview"),
1515            quality=payload.get("quality"),
1516            value=payload.get("value"),
1517            source_data=payload.get("sourceData"),
1518            objectives=payload.get("objectives"),
1519            plug=payload.get("plug"),
1520            metrics=payload.get("metrics"),
1521            gearset=payload.get("gearset"),
1522            sack=payload.get("sack"),
1523            sockets=payload.get("sockets"),
1524            summary=payload.get("summary"),
1525            talent_gird=payload.get("talentGrid"),
1526            investments_stats=payload.get("investmentStats"),
1527            perks=payload.get("perks"),
1528            animations=payload.get("animations", []),
1529            links=payload.get("links", []),
1530        )
1531
1532    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1533        self, payload: typedefs.JSONObject, /
1534    ) -> entity.InventoryEntity:
1535        props = self._set_entity_attrs(payload)
1536        objects = self._deserialize_inventory_item_objects(payload)
1537
1538        collectible_hash: typing.Optional[int] = None
1539        if raw_collectible_hash := payload.get("collectibleHash"):
1540            collectible_hash = int(raw_collectible_hash)
1541
1542        secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1543        if raw_second_icon := payload.get("secondaryIcon"):
1544            secondary_icon = assets.Image(raw_second_icon)
1545
1546        secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1547        if raw_second_overlay := payload.get("secondaryOverlay"):
1548            secondary_overlay = assets.Image(raw_second_overlay)
1549
1550        secondary_special: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1551        if raw_second_special := payload.get("secondarySpecial"):
1552            secondary_special = assets.Image(raw_second_special)
1553
1554        screenshot: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1555        if raw_screenshot := payload.get("screenshot"):
1556            screenshot = assets.Image(raw_screenshot)
1557
1558        watermark_icon: typing.Optional[assets.Image] = None
1559        if raw_watermark_icon := payload.get("iconWatermark"):
1560            watermark_icon = assets.Image(raw_watermark_icon)
1561
1562        watermark_shelved: typing.Optional[assets.Image] = None
1563        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1564            watermark_shelved = assets.Image(raw_watermark_shelved)
1565
1566        about: undefined.UndefinedOr[str] = undefined.UNDEFINED
1567        if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown(
1568            raw_about
1569        ):
1570            about = raw_about
1571
1572        ui_item_style: undefined.UndefinedOr[str] = undefined.UNDEFINED
1573        if (
1574            raw_ui_style := payload.get("uiItemDisplayStyle")
1575        ) and not typedefs.is_unknown(raw_ui_style):
1576            ui_item_style = raw_ui_style
1577
1578        tier_and_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1579        if (
1580            raw_tier_and_name := payload.get("itemTypeAndTierDisplayName")
1581        ) and not typedefs.is_unknown(raw_tier_and_name):
1582            tier_and_name = raw_tier_and_name
1583
1584        type_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1585        if (
1586            raw_type_name := payload.get("itemTypeDisplayName")
1587        ) and not typedefs.is_unknown(raw_type_name):
1588            type_name = raw_type_name
1589
1590        display_source: undefined.UndefinedOr[str] = undefined.UNDEFINED
1591        if (
1592            raw_display_source := payload.get("displaySource")
1593        ) and not typedefs.is_unknown(raw_display_source):
1594            display_source = raw_display_source
1595
1596        lorehash: typing.Optional[int] = None
1597        if raw_lore_hash := payload.get("loreHash"):
1598            lorehash = int(raw_lore_hash)
1599
1600        summary_hash: typing.Optional[int] = None
1601        if raw_summary_hash := payload.get("summaryItemHash"):
1602            summary_hash = raw_summary_hash
1603
1604        breaker_type_hash: typing.Optional[int] = None
1605        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1606            breaker_type_hash = int(raw_breaker_type_hash)
1607
1608        damage_types: typing.Optional[collections.Sequence[int]] = None
1609        if raw_damage_types := payload.get("damageTypes"):
1610            damage_types = [int(type_) for type_ in raw_damage_types]
1611
1612        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1613        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1614            damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes]
1615
1616        default_damagetype_hash: typing.Optional[int] = None
1617        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1618            default_damagetype_hash = int(raw_defaultdmg_hash)
1619
1620        emblem_objective_hash: typing.Optional[int] = None
1621        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1622            emblem_objective_hash = int(raw_emblem_obj_hash)
1623
1624        tier_type: typing.Optional[enums.TierType] = None
1625        tier: typing.Optional[enums.ItemTier] = None
1626        bucket_hash: typing.Optional[int] = None
1627        recovery_hash: typing.Optional[int] = None
1628        tier_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1629        isinstance_item: bool = False
1630        expire_tool_tip: undefined.UndefinedOr[str] = undefined.UNDEFINED
1631        expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.UNDEFINED
1632        suppress_expiration: bool = False
1633        max_stack_size: typing.Optional[int] = None
1634        stack_label: undefined.UndefinedOr[str] = undefined.UNDEFINED
1635
1636        if inventory := payload.get("inventory"):
1637            tier_type = enums.TierType(int(inventory["tierType"]))
1638            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1639            bucket_hash = int(inventory["bucketTypeHash"])
1640            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1641            tier_name = inventory["tierTypeName"]
1642            isinstance_item = inventory["isInstanceItem"]
1643            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1644            max_stack_size = int(inventory["maxStackSize"])
1645
1646            try:
1647                stack_label = inventory["stackUniqueLabel"]
1648            except KeyError:
1649                pass
1650
1651        return entity.InventoryEntity(
1652            net=self._net,
1653            collectible_hash=collectible_hash,
1654            name=props.name,
1655            about=about,
1656            emblem_objective_hash=emblem_objective_hash,
1657            suppress_expiration=suppress_expiration,
1658            max_stack_size=max_stack_size,
1659            stack_label=stack_label,
1660            tier=tier,
1661            tier_type=tier_type,
1662            tier_name=tier_name,
1663            bucket_hash=bucket_hash,
1664            recovery_bucket_hash=recovery_hash,
1665            isinstance_item=isinstance_item,
1666            expire_in_orbit_message=expire_in_orbit_message,
1667            expiration_tooltip=expire_tool_tip,
1668            lore_hash=lorehash,
1669            type_and_tier_name=tier_and_name,
1670            summary_hash=summary_hash,
1671            ui_display_style=ui_item_style,
1672            type_name=type_name,
1673            breaker_type_hash=breaker_type_hash,
1674            description=props.description,
1675            display_source=display_source,
1676            hash=props.hash,
1677            damage_types=damage_types,
1678            index=props.index,
1679            icon=props.icon,
1680            has_icon=props.has_icon,
1681            screenshot=screenshot,
1682            watermark_icon=watermark_icon,
1683            watermark_shelved=watermark_shelved,
1684            secondary_icon=secondary_icon,
1685            secondary_overlay=secondary_overlay,
1686            secondary_special=secondary_special,
1687            type=enums.ItemType(int(payload["itemType"])),
1688            trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])],
1689            trait_ids=[trait for trait in payload.get("traitIds", [])],
1690            category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]],
1691            item_class=enums.Class(int(payload["classType"])),
1692            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1693            breaker_type=int(payload["breakerType"]),
1694            default_damagetype=int(payload["defaultDamageType"]),
1695            default_damagetype_hash=default_damagetype_hash,
1696            damagetype_hashes=damagetype_hashes,
1697            tooltip_notifications=payload["tooltipNotifications"],
1698            not_transferable=payload["nonTransferrable"],
1699            allow_actions=payload["allowActions"],
1700            is_equippable=payload["equippable"],
1701            objects=objects,
1702            background_colors=payload.get("backgroundColor", {}),
1703            season_hash=payload.get("seasonHash"),
1704            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1705        )
1706
1707    def deserialize_objective_entity(
1708        self, payload: typedefs.JSONObject, /
1709    ) -> entity.ObjectiveEntity:
1710        props = self._set_entity_attrs(payload)
1711        return entity.ObjectiveEntity(
1712            net=self._net,
1713            hash=props.hash,
1714            index=props.index,
1715            description=props.description,
1716            name=props.name,
1717            has_icon=props.has_icon,
1718            icon=props.icon,
1719            unlock_value_hash=payload["unlockValueHash"],
1720            completion_value=payload["completionValue"],
1721            scope=entity.GatingScope(int(payload["scope"])),
1722            location_hash=payload["locationHash"],
1723            allowed_negative_value=payload["allowNegativeValue"],
1724            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1725            counting_downward=payload["isCountingDownward"],
1726            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1727            progress_description=payload["progressDescription"],
1728            perks=payload["perks"],
1729            stats=payload["stats"],
1730            minimum_visibility=payload["minimumVisibilityThreshold"],
1731            allow_over_completion=payload["allowOvercompletion"],
1732            show_value_style=payload["showValueOnComplete"],
1733            display_only_objective=payload["isDisplayOnlyObjective"],
1734            complete_value_style=entity.ValueUIStyle(
1735                int(payload["completedValueStyle"])
1736            ),
1737            progress_value_style=entity.ValueUIStyle(
1738                int(payload["inProgressValueStyle"])
1739            ),
1740            ui_label=payload["uiLabel"],
1741            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1742        )
1743
1744    def _deserialize_activity_values(
1745        self, payload: typedefs.JSONObject, /
1746    ) -> activity.ActivityValues:
1747        team: typing.Optional[int] = None
1748        if raw_team := payload.get("team"):
1749            team = raw_team["basic"]["value"]
1750        return activity.ActivityValues(
1751            assists=payload["assists"]["basic"]["value"],
1752            deaths=payload["deaths"]["basic"]["value"],
1753            kills=payload["kills"]["basic"]["value"],
1754            is_completed=bool(payload["completed"]["basic"]["value"]),
1755            opponents_defeated=payload["opponentsDefeated"]["basic"]["value"],
1756            efficiency=payload["efficiency"]["basic"]["value"],
1757            kd_ratio=payload["killsDeathsRatio"]["basic"]["value"],
1758            kd_assists=payload["killsDeathsAssists"]["basic"]["value"],
1759            score=payload["score"]["basic"]["value"],
1760            duration=payload["activityDurationSeconds"]["basic"]["displayValue"],
1761            team=team,
1762            completion_reason=payload["completionReason"]["basic"]["displayValue"],
1763            fireteam_id=payload["fireteamId"]["basic"]["value"],
1764            start_seconds=payload["startSeconds"]["basic"]["value"],
1765            played_time=payload["timePlayedSeconds"]["basic"]["displayValue"],
1766            player_count=payload["playerCount"]["basic"]["value"],
1767            team_score=payload["teamScore"]["basic"]["value"],
1768        )
1769
1770    def deserialize_activity(
1771        self,
1772        payload: typedefs.JSONObject,
1773        /,
1774    ) -> activity.Activity:
1775        period = time.clean_date(payload["period"])
1776        details = payload["activityDetails"]
1777        ref_id = int(details["referenceId"])
1778        instance_id = int(details["instanceId"])
1779        mode = enums.GameMode(details["mode"])
1780        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1781        is_private = details["isPrivate"]
1782        membership_type = enums.MembershipType(int(details["membershipType"]))
1783
1784        # Since we're using the same fields for post activity method
1785        # this check is required since post activity doesn't values values
1786        values = self._deserialize_activity_values(payload["values"])
1787
1788        return activity.Activity(
1789            net=self._net,
1790            hash=ref_id,
1791            instance_id=instance_id,
1792            mode=mode,
1793            modes=modes,
1794            is_private=is_private,
1795            membership_type=membership_type,
1796            occurred_at=period,
1797            values=values,
1798        )
1799
1800    def deserialize_activities(
1801        self, payload: typedefs.JSONObject
1802    ) -> iterators.Iterator[activity.Activity]:
1803        return iterators.Iterator(
1804            [
1805                self.deserialize_activity(activity_)
1806                for activity_ in payload["activities"]
1807            ]
1808        )
1809
1810    def deserialize_extended_weapon_values(
1811        self, payload: typedefs.JSONObject
1812    ) -> activity.ExtendedWeaponValues:
1813        assists: typing.Optional[int] = None
1814        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1815            assists = raw_assists["basic"]["value"]
1816        assists_damage: typing.Optional[int] = None
1817
1818        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1819            assists_damage = raw_assists_damage["basic"]["value"]
1820
1821        return activity.ExtendedWeaponValues(
1822            reference_id=int(payload["referenceId"]),
1823            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1824            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1825                "value"
1826            ],
1827            assists=assists,
1828            assists_damage=assists_damage,
1829            precision_kills_percentage=(
1830                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1831                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1832                    "displayValue"
1833                ],
1834            ),
1835        )
1836
1837    def _deserialize_extended_values(
1838        self, payload: typedefs.JSONObject
1839    ) -> activity.ExtendedValues:
1840        weapons: typing.Optional[
1841            collections.Collection[activity.ExtendedWeaponValues]
1842        ] = None
1843
1844        if raw_weapons := payload.get("weapons"):
1845            weapons = [
1846                self.deserialize_extended_weapon_values(value) for value in raw_weapons
1847            ]
1848
1849        return activity.ExtendedValues(
1850            precision_kills=payload["values"]["precisionKills"]["basic"]["value"],
1851            grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"],
1852            melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"],
1853            super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"],
1854            ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"],
1855            weapons=weapons,
1856        )
1857
1858    def deserialize_post_activity_player(
1859        self, payload: typedefs.JSONObject, /
1860    ) -> activity.PostActivityPlayer:
1861        player = payload["player"]
1862
1863        class_hash: typedefs.NoneOr[int] = None
1864        if (class_hash := player.get("classHash")) is not None:
1865            class_hash = class_hash
1866
1867        race_hash: typedefs.NoneOr[int] = None
1868        if (race_hash := player.get("raceHash")) is not None:
1869            race_hash = race_hash
1870
1871        gender_hash: typedefs.NoneOr[int] = None
1872        if (gender_hash := player.get("genderHash")) is not None:
1873            gender_hash = gender_hash
1874
1875        character_class: undefined.UndefinedOr[str] = undefined.UNDEFINED
1876        if (
1877            character_class := player.get("characterClass")
1878        ) and not typedefs.is_unknown(character_class):
1879            character_class = character_class
1880
1881        character_level: typedefs.NoneOr[int] = None
1882        if (character_level := player.get("characterLevel")) is not None:
1883            character_level = character_level
1884
1885        return activity.PostActivityPlayer(
1886            standing=int(payload["standing"]),
1887            score=int(payload["score"]["basic"]["value"]),
1888            character_id=payload["characterId"],
1889            destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]),
1890            character_class=character_class,
1891            character_level=character_level,
1892            race_hash=race_hash,
1893            gender_hash=gender_hash,
1894            class_hash=class_hash,
1895            light_level=int(player["lightLevel"]),
1896            emblem_hash=int(player["emblemHash"]),
1897            values=self._deserialize_activity_values(payload["values"]),
1898            extended_values=self._deserialize_extended_values(payload["extended"]),
1899        )
1900
1901    def _deserialize_post_activity_team(
1902        self, payload: typedefs.JSONObject
1903    ) -> activity.PostActivityTeam:
1904        return activity.PostActivityTeam(
1905            id=payload["teamId"],
1906            is_defeated=bool(payload["standing"]["basic"]["value"]),
1907            score=int(payload["score"]["basic"]["value"]),
1908            name=payload["teamName"],
1909        )
1910
1911    def deserialize_post_activity(
1912        self, payload: typedefs.JSONObject
1913    ) -> activity.PostActivity:
1914        period = time.clean_date(payload["period"])
1915        details = payload["activityDetails"]
1916        ref_id = int(details["referenceId"])
1917        instance_id = int(details["instanceId"])
1918        mode = enums.GameMode(details["mode"])
1919        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1920        is_private = details["isPrivate"]
1921        membership_type = enums.MembershipType(int(details["membershipType"]))
1922        return activity.PostActivity(
1923            net=self._net,
1924            hash=ref_id,
1925            membership_type=membership_type,
1926            instance_id=instance_id,
1927            mode=mode,
1928            modes=modes,
1929            is_private=is_private,
1930            occurred_at=period,
1931            starting_phase=int(payload["startingPhaseIndex"]),
1932            players=[
1933                self.deserialize_post_activity_player(player)
1934                for player in payload["entries"]
1935            ],
1936            teams=[
1937                self._deserialize_post_activity_team(team) for team in payload["teams"]
1938            ],
1939        )
1940
1941    def _deserialize_aggregated_activity_values(
1942        self, payload: typedefs.JSONObject
1943    ) -> activity.AggregatedActivityValues:
1944        # This ID is always the same for all aggregated values.
1945        activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"])
1946
1947        return activity.AggregatedActivityValues(
1948            id=activity_id,
1949            fastest_completion_time=(
1950                int(payload["fastestCompletionMsForActivity"]["basic"]["value"]),
1951                payload["fastestCompletionMsForActivity"]["basic"]["displayValue"],
1952            ),
1953            completions=int(payload["activityCompletions"]["basic"]["value"]),
1954            kills=int(payload["activityKills"]["basic"]["value"]),
1955            deaths=int(payload["activityDeaths"]["basic"]["value"]),
1956            assists=int(payload["activityAssists"]["basic"]["value"]),
1957            seconds_played=(
1958                int(payload["activitySecondsPlayed"]["basic"]["value"]),
1959                payload["activitySecondsPlayed"]["basic"]["displayValue"],
1960            ),
1961            wins=int(payload["activityWins"]["basic"]["value"]),
1962            goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]),
1963            special_actions=int(payload["activitySpecialActions"]["basic"]["value"]),
1964            best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]),
1965            best_single_score=int(
1966                payload["activityBestSingleGameScore"]["basic"]["value"]
1967            ),
1968            goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]),
1969            special_score=int(payload["activitySpecialScore"]["basic"]["value"]),
1970            kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]),
1971            kd_ratio=float(
1972                payload["activityKillsDeathsAssists"]["basic"]["displayValue"]
1973            ),
1974            precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]),
1975        )
1976
1977    def deserialize_aggregated_activity(
1978        self, payload: typedefs.JSONObject
1979    ) -> activity.AggregatedActivity:
1980        return activity.AggregatedActivity(
1981            hash=int(payload["activityHash"]),
1982            values=self._deserialize_aggregated_activity_values(payload["values"]),
1983        )
1984
1985    def deserialize_aggregated_activities(
1986        self, payload: typedefs.JSONObject
1987    ) -> iterators.Iterator[activity.AggregatedActivity]:
1988        return iterators.Iterator(
1989            [
1990                self.deserialize_aggregated_activity(activity)
1991                for activity in payload["activities"]
1992            ]
1993        )
1994
1995    def deserialize_linked_profiles(
1996        self, payload: typedefs.JSONObject
1997    ) -> profile.LinkedProfile:
1998        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
1999        error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2000        profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2001
2002        if raw_profile := payload.get("profiles"):
2003            for pfile in raw_profile:
2004                profiles_vec.append(self.deserialize_destiny_membership(pfile))
2005
2006        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
2007            for raw_error_pfile in raw_profiles_with_errors:
2008                if error_pfile := raw_error_pfile.get("infoCard"):
2009                    error_profiles_vec.append(
2010                        self.deserialize_destiny_membership(error_pfile)
2011                    )
2012
2013        return profile.LinkedProfile(
2014            net=self._net,
2015            bungie=bungie_user,
2016            profiles=profiles_vec,
2017            profiles_with_errors=error_profiles_vec,
2018        )
2019
2020    def deserialize_clan_banners(
2021        self, payload: typedefs.JSONObject
2022    ) -> collections.Sequence[clans.ClanBanner]:
2023        banners_seq: typing.MutableSequence[clans.ClanBanner] = []
2024        if banners := payload.get("clanBannerDecals"):
2025            for k, v in banners.items():
2026                banner_obj = clans.ClanBanner(
2027                    id=int(k),
2028                    foreground=assets.Image(v["foregroundPath"]),
2029                    background=assets.Image(v["backgroundPath"]),
2030                )
2031                banners_seq.append(banner_obj)
2032        return banners_seq
2033
2034    def deserialize_public_milestone_content(
2035        self, payload: typedefs.JSONObject
2036    ) -> milestones.MilestoneContent:
2037        items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None
2038        if raw_categories := payload.get("itemCategories"):
2039            for item in raw_categories:
2040                title = undefined.UNDEFINED
2041                if raw_title := item.get("title"):
2042                    if raw_title != typedefs.Unknown:
2043                        title = raw_title
2044                if raw_hashes := item.get("itemHashes"):
2045                    hashes: collections.Sequence[int] = raw_hashes
2046
2047                items_categoris = milestones.MilestoneItems(title=title, hashes=hashes)
2048
2049        about = undefined.UNDEFINED
2050        if (raw_about := payload["about"]) != typedefs.Unknown:
2051            about = raw_about
2052
2053        status = undefined.UNDEFINED
2054        if (raw_status := payload["status"]) != typedefs.Unknown:
2055            status = raw_status
2056
2057        tips: typing.MutableSequence[undefined.UndefinedOr[str]] = []
2058        if raw_tips := payload.get("tips"):
2059            for raw_tip in raw_tips:
2060                if raw_tip == typedefs.Unknown:
2061                    raw_tip = undefined.UNDEFINED
2062                tips.append(raw_tip)
2063
2064        return milestones.MilestoneContent(
2065            about=about, status=status, tips=tips, items=items_categoris
2066        )
2067
2068    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2069        name = undefined.UNDEFINED
2070        if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown:
2071            name = raw_name
2072
2073        bungie_user: typedefs.NoneOr[user.BungieUser] = None
2074
2075        if raw_bungie_user := payload.get("bungieNetUser"):
2076            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2077
2078        return friends.Friend(
2079            net=self._net,
2080            id=int(payload["lastSeenAsMembershipId"]),
2081            name=name,
2082            code=payload.get("bungieGlobalDisplayNameCode"),
2083            relationship=enums.Relationship(payload["relationship"]),
2084            user=bungie_user,
2085            online_status=enums.Presence(payload["onlineStatus"]),
2086            online_title=payload["onlineTitle"],
2087            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2088        )
2089
2090    def deserialize_friends(
2091        self, payload: typedefs.JSONObject
2092    ) -> collections.Sequence[friends.Friend]:
2093        mut_seq: typing.MutableSequence[friends.Friend] = []
2094        if raw_friends := payload.get("friends"):
2095            for friend in raw_friends:
2096                mut_seq.append(self.deserialize_friend(friend))
2097        return mut_seq
2098
2099    def deserialize_friend_requests(
2100        self, payload: typedefs.JSONObject
2101    ) -> friends.FriendRequestView:
2102        incoming: typing.MutableSequence[friends.Friend] = []
2103        outgoing: typing.MutableSequence[friends.Friend] = []
2104
2105        if raw_incoming_requests := payload.get("incomingRequests"):
2106            for incoming_request in raw_incoming_requests:
2107                incoming.append(self.deserialize_friend(incoming_request))
2108
2109        if raw_outgoing_requests := payload.get("outgoingRequests"):
2110            for outgoing_request in raw_outgoing_requests:
2111                outgoing.append(self.deserialize_friend(outgoing_request))
2112
2113        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
2114
2115    def _set_fireteam_fields(
2116        self, payload: typedefs.JSONObject, total_results: typing.Optional[int] = None
2117    ) -> fireteams.Fireteam:
2118        activity_type = fireteams.FireteamActivity(payload["activityType"])
2119        return fireteams.Fireteam(
2120            id=int(payload["fireteamId"]),
2121            group_id=int(payload["groupId"]),
2122            platform=fireteams.FireteamPlatform(payload["platform"]),
2123            is_immediate=payload["isImmediate"],
2124            activity_type=activity_type,
2125            owner_id=int(payload["ownerMembershipId"]),
2126            player_slot_count=payload["playerSlotCount"],
2127            available_player_slots=payload["availablePlayerSlotCount"],
2128            available_alternate_slots=payload["availableAlternateSlotCount"],
2129            title=payload["title"],
2130            date_created=time.clean_date(payload["dateCreated"]),
2131            is_public=payload["isPublic"],
2132            locale=fireteams.FireteamLanguage(payload["locale"]),
2133            is_valid=payload["isValid"],
2134            last_modified=time.clean_date(payload["datePlayerModified"]),
2135            total_results=total_results or 0,
2136        )
2137
2138    def deserialize_fireteams(
2139        self, payload: typedefs.JSONObject
2140    ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]:
2141        fireteams_: typing.MutableSequence[fireteams.Fireteam] = []
2142
2143        result: list[typedefs.JSONObject]
2144        if not (result := payload["results"]):
2145            return None
2146        for elem in result:
2147            fireteams_.append(
2148                self._set_fireteam_fields(
2149                    elem, total_results=int(payload["totalResults"])
2150                )
2151            )
2152        return fireteams_
2153
2154    def deserialize_fireteam_destiny_users(
2155        self, payload: typedefs.JSONObject
2156    ) -> fireteams.FireteamUser:
2157        destiny_obj = self.deserialize_destiny_membership(payload)
2158        # We could helpers.just return a DestinyMembership object but this is
2159        # missing the fireteam display name and id fields.
2160        return fireteams.FireteamUser(
2161            net=self._net,
2162            id=destiny_obj.id,
2163            code=destiny_obj.code,
2164            icon=destiny_obj.icon,
2165            types=destiny_obj.types,
2166            type=destiny_obj.type,
2167            is_public=destiny_obj.is_public,
2168            crossave_override=destiny_obj.crossave_override,
2169            name=destiny_obj.name,
2170            last_seen_name=destiny_obj.last_seen_name,
2171            fireteam_display_name=payload["FireteamDisplayName"],
2172            fireteam_membership_id=enums.MembershipType(
2173                payload["FireteamMembershipType"]
2174            ),
2175        )
2176
2177    def deserialize_fireteam_members(
2178        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2179    ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]:
2180        members_: list[fireteams.FireteamMember] = []
2181        if members := payload.get("Members" if not alternatives else "Alternates"):
2182            for member in members:
2183                bungie_fields = self.deserialize_partial_bungie_user(member)
2184                members_fields = fireteams.FireteamMember(
2185                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2186                    has_microphone=member["hasMicrophone"],
2187                    character_id=int(member["characterId"]),
2188                    date_joined=time.clean_date(member["dateJoined"]),
2189                    last_platform_invite_date=time.clean_date(
2190                        member["lastPlatformInviteAttemptDate"]
2191                    ),
2192                    last_platform_invite_result=int(
2193                        member["lastPlatformInviteAttemptResult"]
2194                    ),
2195                    net=self._net,
2196                    name=bungie_fields.name,
2197                    id=bungie_fields.id,
2198                    icon=bungie_fields.icon,
2199                    is_public=bungie_fields.is_public,
2200                    crossave_override=bungie_fields.crossave_override,
2201                    types=bungie_fields.types,
2202                    type=bungie_fields.type,
2203                )
2204                members_.append(members_fields)
2205        else:
2206            return None
2207        return members_
2208
2209    def deserialize_available_fireteams(
2210        self,
2211        data: typedefs.JSONObject,
2212        *,
2213        no_results: bool = False,
2214    ) -> typing.Union[
2215        fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam]
2216    ]:
2217        fireteams_: list[fireteams.AvailableFireteam] = []
2218
2219        # This needs to be used outside the results
2220        # JSON key.
2221        if no_results is True:
2222            payload = data
2223
2224        if result := payload.get("results"):
2225            for fireteam in result:
2226                found_fireteams = self._set_fireteam_fields(fireteam["Summary"])
2227                fireteams_fields = fireteams.AvailableFireteam(
2228                    id=found_fireteams.id,
2229                    group_id=found_fireteams.group_id,
2230                    platform=found_fireteams.platform,
2231                    activity_type=found_fireteams.activity_type,
2232                    is_immediate=found_fireteams.is_immediate,
2233                    is_public=found_fireteams.is_public,
2234                    is_valid=found_fireteams.is_valid,
2235                    owner_id=found_fireteams.owner_id,
2236                    player_slot_count=found_fireteams.player_slot_count,
2237                    available_player_slots=found_fireteams.available_player_slots,
2238                    available_alternate_slots=found_fireteams.available_alternate_slots,
2239                    title=found_fireteams.title,
2240                    date_created=found_fireteams.date_created,
2241                    locale=found_fireteams.locale,
2242                    last_modified=found_fireteams.last_modified,
2243                    total_results=found_fireteams.total_results,
2244                    members=self.deserialize_fireteam_members(payload),
2245                    alternatives=self.deserialize_fireteam_members(
2246                        payload, alternatives=True
2247                    ),
2248                )
2249            fireteams_.append(fireteams_fields)
2250            if no_results:
2251                return fireteams_fields
2252        return fireteams_
2253
2254    def deserialize_fireteam_party(
2255        self, payload: typedefs.JSONObject
2256    ) -> fireteams.FireteamParty:
2257        last_destination_hash: typing.Optional[int] = None
2258        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2259            last_destination_hash = int(raw_dest_hash)
2260
2261        return fireteams.FireteamParty(
2262            members=[
2263                self._deserialize_fireteam_party_member(member)
2264                for member in payload["partyMembers"]
2265            ],
2266            activity=self._deserialize_fireteam_party_current_activity(
2267                payload["currentActivity"]
2268            ),
2269            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2270            last_destination_hash=last_destination_hash,
2271            tracking=payload["tracking"],
2272        )
2273
2274    def _deserialize_fireteam_party_member(
2275        self, payload: typedefs.JSONObject
2276    ) -> fireteams.FireteamPartyMember:
2277        status = fireteams.FireteamPartyMemberState(payload["status"])
2278        displayname: undefined.UndefinedOr[str] = undefined.UNDEFINED
2279        if raw_name := payload.get("displayName"):
2280            displayname = raw_name
2281
2282        return fireteams.FireteamPartyMember(
2283            membership_id=int(payload["membershipId"]),
2284            emblem_hash=int(payload["emblemHash"]),
2285            status=status,
2286            display_name=displayname,
2287        )
2288
2289    def _deserialize_fireteam_party_current_activity(
2290        self, payload: typedefs.JSONObject
2291    ) -> fireteams.FireteamPartyCurrentActivity:
2292        start_date: typing.Optional[datetime.datetime] = None
2293        if raw_start_date := payload.get("startTime"):
2294            start_date = time.clean_date(raw_start_date)
2295
2296        end_date: typing.Optional[datetime.datetime] = None
2297        if raw_end_date := payload.get("endTime"):
2298            end_date = time.clean_date(raw_end_date)
2299        return fireteams.FireteamPartyCurrentActivity(
2300            start_time=start_date,
2301            end_time=end_date,
2302            score=float(payload["score"]),
2303            highest_opposing_score=float(payload["highestOpposingFactionScore"]),
2304            opponenst_count=int(payload["numberOfOpponents"]),
2305            player_count=int(payload["numberOfPlayers"]),
2306        )
2307
2308    def _deserialize_fireteam_party_settings(
2309        self, payload: typedefs.JSONObject
2310    ) -> fireteams.FireteamPartySettings:
2311        closed_reasons = enums.ClosedReasons(payload["closedReasons"])
2312        return fireteams.FireteamPartySettings(
2313            open_slots=int(payload["openSlots"]),
2314            privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])),
2315            closed_reasons=closed_reasons,
2316        )
2317
2318    def deserialize_seasonal_artifact(
2319        self, payload: typedefs.JSONObject
2320    ) -> season.Artifact:
2321        if raw_artifact := payload.get("seasonalArtifact"):
2322            if points := raw_artifact.get("pointProgression"):
2323                points_prog = progressions.Progression(
2324                    hash=points["progressionHash"],
2325                    level=points["level"],
2326                    cap=points["levelCap"],
2327                    daily_limit=points["dailyLimit"],
2328                    weekly_limit=points["weeklyLimit"],
2329                    current_progress=points["currentProgress"],
2330                    daily_progress=points["dailyProgress"],
2331                    needed=points["progressToNextLevel"],
2332                    next_level=points["nextLevelAt"],
2333                )
2334
2335            if bonus := raw_artifact.get("powerBonusProgression"):
2336                power_bonus_prog = progressions.Progression(
2337                    hash=bonus["progressionHash"],
2338                    level=bonus["level"],
2339                    cap=bonus["levelCap"],
2340                    daily_limit=bonus["dailyLimit"],
2341                    weekly_limit=bonus["weeklyLimit"],
2342                    current_progress=bonus["currentProgress"],
2343                    daily_progress=bonus["dailyProgress"],
2344                    needed=bonus["progressToNextLevel"],
2345                    next_level=bonus["nextLevelAt"],
2346                )
2347            artifact = season.Artifact(
2348                net=self._net,
2349                hash=raw_artifact["artifactHash"],
2350                power_bonus=raw_artifact["powerBonus"],
2351                acquired_points=raw_artifact["pointsAcquired"],
2352                bonus=power_bonus_prog,
2353                points=points_prog,
2354            )
2355        return artifact
2356
2357    def deserialize_profile_progression(
2358        self, payload: typedefs.JSONObject
2359    ) -> profile.ProfileProgression:
2360        return profile.ProfileProgression(
2361            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2362            checklist={
2363                int(check_id): checklists
2364                for check_id, checklists in payload["data"]["checklists"].items()
2365            },
2366        )
2367
2368    def deserialize_instanced_item(
2369        self, payload: typedefs.JSONObject
2370    ) -> items.ItemInstance:
2371        damage_type_hash: typing.Optional[int] = None
2372        if raw_damagetype_hash := payload.get("damageTypeHash"):
2373            damage_type_hash = int(raw_damagetype_hash)
2374
2375        required_hashes: typing.Optional[collections.Collection[int]] = None
2376        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2377            required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes]
2378
2379        breaker_type: typing.Optional[items.ItemBreakerType] = None
2380        if raw_break_type := payload.get("breakerType"):
2381            breaker_type = items.ItemBreakerType(int(raw_break_type))
2382
2383        breaker_type_hash: typing.Optional[int] = None
2384        if raw_break_type_hash := payload.get("breakerTypeHash"):
2385            breaker_type_hash = int(raw_break_type_hash)
2386
2387        energy: typing.Optional[items.ItemEnergy] = None
2388        if raw_energy := payload.get("energy"):
2389            energy = self.deserialize_item_energy(raw_energy)
2390
2391        primary_stats = None
2392        if raw_primary_stats := payload.get("primaryStat"):
2393            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2394
2395        return items.ItemInstance(
2396            damage_type=enums.DamageType(int(payload["damageType"])),
2397            damage_type_hash=damage_type_hash,
2398            primary_stat=primary_stats,
2399            item_level=int(payload["itemLevel"]),
2400            quality=int(payload["quality"]),
2401            is_equipped=payload["isEquipped"],
2402            can_equip=payload["canEquip"],
2403            equip_required_level=int(payload["equipRequiredLevel"]),
2404            required_equip_unlock_hashes=required_hashes,
2405            cant_equip_reason=int(payload["cannotEquipReason"]),
2406            breaker_type=breaker_type,
2407            breaker_type_hash=breaker_type_hash,
2408            energy=energy,
2409        )
2410
2411    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2412        energy_hash: typing.Optional[int] = None
2413        if raw_energy_hash := payload.get("energyTypeHash"):
2414            energy_hash = int(raw_energy_hash)
2415
2416        return items.ItemEnergy(
2417            hash=energy_hash,
2418            type=items.ItemEnergyType(int(payload["energyType"])),
2419            capacity=int(payload["energyCapacity"]),
2420            used_energy=int(payload["energyUsed"]),
2421            unused_energy=int(payload["energyUnused"]),
2422        )
2423
2424    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2425        perk_hash: typing.Optional[int] = None
2426        if raw_perk_hash := payload.get("perkHash"):
2427            perk_hash = int(raw_perk_hash)
2428
2429        return items.ItemPerk(
2430            hash=perk_hash,
2431            icon=assets.Image(payload["iconPath"]),
2432            is_active=payload["isActive"],
2433            is_visible=payload["visible"],
2434        )
2435
2436    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2437        plug_hash: typing.Optional[int] = None
2438        if raw_plug_hash := payload.get("plugHash"):
2439            plug_hash = int(raw_plug_hash)
2440
2441        enable_fail_indexes: typing.Optional[list[int]] = None
2442        if raw_indexes := payload.get("enableFailIndexes"):
2443            enable_fail_indexes = [int(index) for index in raw_indexes]
2444
2445        return items.ItemSocket(
2446            plug_hash=plug_hash,
2447            is_enabled=payload["isEnabled"],
2448            enable_fail_indexes=enable_fail_indexes,
2449            is_visible=payload.get("visible"),
2450        )
2451
2452    def deserialize_item_stats_view(
2453        self, payload: typedefs.JSONObject
2454    ) -> items.ItemStatsView:
2455        return items.ItemStatsView(
2456            stat_hash=payload.get("statHash"), value=payload.get("value")
2457        )
2458
2459    def deserialize_plug_item_state(
2460        self, payload: typedefs.JSONObject
2461    ) -> items.PlugItemState:
2462        item_hash: typing.Optional[int] = None
2463        if raw_item_hash := payload.get("plugItemHash"):
2464            item_hash = int(raw_item_hash)
2465
2466        insert_fail_indexes: typedefs.NoneOr[list[int]] = None
2467        if raw_fail_indexes := payload.get("insertFailIndexes"):
2468            insert_fail_indexes = [int(k) for k in raw_fail_indexes]
2469
2470        enable_fail_indexes: typedefs.NoneOr[list[int]] = None
2471        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2472            enable_fail_indexes = [int(k) for k in raw_enabled_indexes]
2473
2474        return items.PlugItemState(
2475            item_hash=item_hash,
2476            insert_fail_indexes=insert_fail_indexes,
2477            enable_fail_indexes=enable_fail_indexes,
2478            is_enabled=payload["enabled"],
2479            can_insert=payload["canInsert"],
2480        )

The base deserialization factory class for all aiobungie objects.

Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them into a aiobungie.crates Python classes.

Factory(net: aiobungie.traits.Netrunner)
70    def __init__(self, net: traits.Netrunner) -> None:
71        self._net = net
def deserialize_bungie_user(self, data: dict[str, typing.Any]) -> aiobungie.crates.user.BungieUser:
73    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
74        return user.BungieUser(
75            id=int(data["membershipId"]),
76            created_at=time.clean_date(data["firstAccess"]),
77            name=data.get("cachedBungieGlobalDisplayName", undefined.UNDEFINED),
78            is_deleted=data["isDeleted"],
79            about=data["about"],
80            updated_at=time.clean_date(data["lastUpdate"]),
81            psn_name=data.get("psnDisplayName", None),
82            stadia_name=data.get("stadiaDisplayName", None),
83            steam_name=data.get("steamDisplayName", None),
84            twitch_name=data.get("twitchDisplayName", None),
85            blizzard_name=data.get("blizzardDisplayName", None),
86            status=data["statusText"],
87            locale=data["locale"],
88            picture=assets.Image(path=str(data["profilePicturePath"])),
89            code=data.get("cachedBungieGlobalDisplayNameCode", None),
90            unique_name=data.get("uniqueName", None),
91            theme_id=int(data["profileTheme"]),
92            show_activity=bool(data["showActivity"]),
93            theme_name=data["profileThemeName"],
94            display_title=data["userTitleDisplay"],
95        )

Deserialize a raw JSON Bungie.net user only payload into a user object.

This only returns the Bungie.net user and not the Destiny memberships.

Parameters
Returns
def deserialize_partial_bungie_user( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.PartialBungieUser:
 97    def deserialize_partial_bungie_user(
 98        self, payload: typedefs.JSONObject
 99    ) -> user.PartialBungieUser:
100        return user.PartialBungieUser(
101            net=self._net,
102            types=[
103                enums.MembershipType(type_)
104                for type_ in payload.get("applicableMembershipTypes", [])
105            ],
106            name=payload.get("displayName", undefined.UNDEFINED),
107            id=int(payload["membershipId"]),
108            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
109            is_public=payload["isPublic"],
110            icon=assets.Image(payload.get("iconPath", "")),
111            type=enums.MembershipType(payload["membershipType"]),
112        )

Deserialize a raw JSON of a partial bungieNetUserInfo.

A partial user is a bungie.net user payload with missing information from the main BungieUser object.

Parameters
Returns
def deserialize_destiny_membership( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.DestinyMembership:
114    def deserialize_destiny_membership(
115        self, payload: typedefs.JSONObject
116    ) -> user.DestinyMembership:
117        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
118        if (
119            raw_name := payload.get("bungieGlobalDisplayName", "")
120        ) and not typedefs.is_unknown(raw_name):
121            name = raw_name
122
123        return user.DestinyMembership(
124            net=self._net,
125            id=int(payload["membershipId"]),
126            name=name,
127            code=payload.get("bungieGlobalDisplayNameCode", None),
128            last_seen_name=payload.get("LastSeenDisplayName")
129            or payload.get("displayName")  # noqa: W503
130            or "",  # noqa: W503
131            type=enums.MembershipType(payload["membershipType"]),
132            is_public=payload["isPublic"],
133            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
134            icon=assets.Image(payload.get("iconPath", "")),
135            types=[
136                enums.MembershipType(type_)
137                for type_ in payload.get("applicableMembershipTypes", [])
138            ],
139        )

Deserialize a raw JSON of destinyUserInfo destiny membership information.

Parameters
Returns
  • aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
def deserialize_destiny_memberships( self, data: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
141    def deserialize_destiny_memberships(
142        self, data: typedefs.JSONArray
143    ) -> collections.Sequence[user.DestinyMembership]:
144        return [self.deserialize_destiny_membership(membership) for membership in data]

Deserialize a raw JSON payload/array of destinyUserInfo.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
def deserialize_user(self, data: dict[str, typing.Any]) -> aiobungie.crates.user.User:
146    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
147        primary_membership_id: typing.Optional[int] = None
148        if raw_primary_id := data.get("primaryMembershipId"):
149            primary_membership_id = int(raw_primary_id)
150
151        return user.User(
152            bungie=self.deserialize_bungie_user(data["bungieNetUser"]),
153            destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]),
154            primary_membership_id=primary_membership_id,
155        )

Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.

Parameters
Returns
def deserialize_searched_user( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.SearchableDestinyUser:
157    def deserialize_searched_user(
158        self, payload: typedefs.JSONObject
159    ) -> user.SearchableDestinyUser:
160        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
161        if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown(
162            raw_name
163        ):
164            name = raw_name
165
166        code: typing.Optional[int] = None
167        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
168            code = int(raw_code)
169
170        bungie_id: typing.Optional[int] = None
171        if raw_bungie_id := payload.get("bungieNetMembershipId"):
172            bungie_id = int(raw_bungie_id)
173
174        return user.SearchableDestinyUser(
175            name=name,
176            code=code,
177            bungie_id=bungie_id,
178            memberships=self.deserialize_destiny_memberships(
179                payload["destinyMemberships"]
180            ),
181        )

Deserialize the results of user search details.

Parameters
Returns
def deserialize_user_credentials( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
183    def deserialize_user_credentials(
184        self, payload: typedefs.JSONArray
185    ) -> collections.Sequence[user.UserCredentials]:
186        return [
187            user.UserCredentials(
188                type=enums.CredentialType(int(creds["credentialType"])),
189                display_name=creds["credentialDisplayName"],
190                is_public=creds["isPublic"],
191                self_as_string=creds.get("credentialAsString", undefined.UNDEFINED),
192            )
193            for creds in payload
194        ]

Deserialize a JSON array of Bungie user credentials.

Parameters
Returns
def deserialize_user_themes( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
196    def deserialize_user_themes(
197        self, payload: typedefs.JSONArray
198    ) -> collections.Sequence[user.UserThemes]:
199        return [
200            user.UserThemes(
201                id=int(entry["userThemeId"]),
202                name=entry["userThemeName"]
203                if "userThemeName" in entry
204                else undefined.UNDEFINED,
205                description=entry["userThemeDescription"]
206                if "userThemeDescription" in entry
207                else undefined.UNDEFINED,
208            )
209            for entry in payload
210        ]

Deserialize a raw JSON array of Bungie user themes.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
def deserialize_clan(self, payload: dict[str, typing.Any]) -> aiobungie.crates.clans.Clan:
212    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
213        # This is kinda redundant
214        data = payload
215
216        # This is always outside the details.
217        current_user_map: typing.Optional[
218            collections.Mapping[str, clans.ClanMember]
219        ] = None
220        if raw_current_user_map := payload.get("currentUserMemberMap"):
221            current_user_map = {
222                membership_type: self.deserialize_clan_member(membership)
223                for membership_type, membership in raw_current_user_map.items()
224            }
225
226        try:
227            data = payload["detail"]
228        except KeyError:
229            pass
230
231        id = data["groupId"]
232        name = data["name"]
233        created_at = data["creationDate"]
234        member_count = data["memberCount"]
235        about = data["about"]
236        motto = data["motto"]
237        is_public = data["isPublic"]
238        banner = assets.Image(str(data["bannerPath"]))
239        avatar = assets.Image(str(data["avatarPath"]))
240        tags = data["tags"]
241        type = data["groupType"]
242
243        features = data["features"]
244        features_obj = clans.ClanFeatures(
245            max_members=features["maximumMembers"],
246            max_membership_types=features["maximumMembershipsOfGroupType"],
247            capabilities=features["capabilities"],
248            membership_types=features["membershipTypes"],
249            invite_permissions=features["invitePermissionOverride"],
250            update_banner_permissions=features["updateBannerPermissionOverride"],
251            update_culture_permissions=features["updateCulturePermissionOverride"],
252            join_level=features["joinLevel"],
253        )
254
255        information: typedefs.JSONObject = data["clanInfo"]
256        progression: collections.Mapping[int, progressions.Progression] = {
257            int(prog_hash): self.deserialize_progressions(prog)
258            for prog_hash, prog in information["d2ClanProgressions"].items()
259        }
260
261        founder: typedefs.NoneOr[clans.ClanMember] = None
262        if raw_founder := payload.get("founder"):
263            founder = self.deserialize_clan_member(raw_founder)
264
265        return clans.Clan(
266            net=self._net,
267            id=int(id),
268            name=name,
269            type=enums.GroupType(type),
270            created_at=time.clean_date(created_at),
271            member_count=member_count,
272            motto=motto,
273            about=about,
274            is_public=is_public,
275            banner=banner,
276            avatar=avatar,
277            tags=tags,
278            features=features_obj,
279            owner=founder,
280            progressions=progression,
281            call_sign=information["clanCallsign"],
282            banner_data=information["clanBannerData"],
283            chat_security=data["chatSecurity"],
284            conversation_id=int(data["conversationId"]),
285            allow_chat=data["allowChat"],
286            theme=data["theme"],
287            current_user_membership=current_user_map,
288        )

Deserialize a raw JSON payload of Bungie clan information.

Parameters
Returns
def deserialize_clan_member( self, data: dict[str, typing.Any], /) -> aiobungie.crates.clans.ClanMember:
290    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
291        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
292        return clans.ClanMember(
293            net=self._net,
294            last_seen_name=destiny_user.last_seen_name,
295            id=destiny_user.id,
296            name=destiny_user.name,
297            icon=destiny_user.icon,
298            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
299            group_id=int(data["groupId"]),
300            joined_at=time.clean_date(data["joinDate"]),
301            types=destiny_user.types,
302            is_public=destiny_user.is_public,
303            type=destiny_user.type,
304            code=destiny_user.code,
305            is_online=data["isOnline"],
306            crossave_override=destiny_user.crossave_override,
307            bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
308            if "bungieNetUserInfo" in data
309            else None,
310            member_type=enums.ClanMemberType(int(data["memberType"])),
311        )

Deserialize a JSON payload of a clan member information.

Parameters
Returns
def deserialize_clan_members( self, data: dict[str, typing.Any], /) -> Iterator[aiobungie.crates.clans.ClanMember]:
313    def deserialize_clan_members(
314        self, data: typedefs.JSONObject, /
315    ) -> iterators.Iterator[clans.ClanMember]:
316        return iterators.Iterator(
317            [self.deserialize_clan_member(member) for member in data["results"]]
318        )

Deserialize a JSON payload of a clan members information.

Parameters
Returns
def deserialize_group_member( self, payload: dict[str, typing.Any]) -> aiobungie.crates.clans.GroupMember:
320    def deserialize_group_member(
321        self, payload: typedefs.JSONObject
322    ) -> clans.GroupMember:
323        member = payload["member"]
324        return clans.GroupMember(
325            net=self._net,
326            join_date=time.clean_date(member["joinDate"]),
327            group_id=int(member["groupId"]),
328            member_type=enums.ClanMemberType(member["memberType"]),
329            is_online=member["isOnline"],
330            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
331            inactive_memberships=payload.get("areAllMembershipsInactive", None),
332            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
333            group=self.deserialize_clan(payload["group"]),
334        )

Deserialize a JSON payload of group information for a member.

Parameters
Returns
def deserialize_clan_conversations( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
352    def deserialize_clan_conversations(
353        self, payload: typedefs.JSONArray
354    ) -> collections.Sequence[clans.ClanConversation]:
355        return [self._deserialize_clan_conversation(conv) for conv in payload]

Deserialize a JSON array of a clan conversations information.

Parameters
Returns
def deserialize_app_owner( self, payload: dict[str, typing.Any]) -> aiobungie.crates.application.ApplicationOwner:
357    def deserialize_app_owner(
358        self, payload: typedefs.JSONObject
359    ) -> application.ApplicationOwner:
360        return application.ApplicationOwner(
361            net=self._net,
362            name=payload.get("bungieGlobalDisplayName", undefined.UNDEFINED),
363            id=int(payload["membershipId"]),
364            type=enums.MembershipType(payload["membershipType"]),
365            icon=assets.Image(str(payload["iconPath"])),
366            is_public=payload["isPublic"],
367            code=payload.get("bungieGlobalDisplayNameCode", None),
368        )

Deserialize a JSON payload of Bungie Developer portal application owner information.

Parameters
Returns
  • aiobungie.crates.application.ApplicationOwner: An application owner.
def deserialize_app( self, payload: dict[str, typing.Any]) -> aiobungie.crates.application.Application:
370    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
371        return application.Application(
372            id=int(payload["applicationId"]),
373            name=payload["name"],
374            link=payload["link"],
375            status=payload["status"],
376            redirect_url=payload.get("redirectUrl", None),
377            created_at=time.clean_date(str(payload["creationDate"])),
378            published_at=time.clean_date(str(payload["firstPublished"])),
379            owner=self.deserialize_app_owner(payload["team"][0]["user"]),  # type: ignore
380            scope=payload.get("scope", undefined.UNDEFINED),
381        )

Deserialize a JSON payload of Bungie Developer portal application information.

Parameters
Returns
  • aiobungie.crates.application.Application: An application.
def deserialize_profile( self, payload: dict[str, typing.Any], /) -> Optional[aiobungie.crates.profile.Profile]:
404    def deserialize_profile(
405        self, payload: typedefs.JSONObject, /
406    ) -> typing.Optional[profile.Profile]:
407        if (raw_profile := payload.get("data")) is None:
408            return None
409
410        payload = raw_profile
411        id = int(payload["userInfo"]["membershipId"])
412        name = payload["userInfo"]["displayName"]
413        is_public = payload["userInfo"]["isPublic"]
414        type = enums.MembershipType(payload["userInfo"]["membershipType"])
415        last_played = time.clean_date(str(payload["dateLastPlayed"]))
416        character_ids = [int(cid) for cid in payload["characterIds"]]
417        power_cap = payload["currentSeasonRewardPowerCap"]
418
419        return profile.Profile(
420            id=int(id),
421            name=name,
422            is_public=is_public,
423            type=type,
424            last_played=last_played,
425            character_ids=character_ids,
426            power_cap=power_cap,
427            net=self._net,
428        )

Deserialize a JSON payload of Bungie.net profile information.

Parameters
Returns
def deserialize_profile_item( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.ProfileItemImpl:
430    def deserialize_profile_item(
431        self, payload: typedefs.JSONObject
432    ) -> profile.ProfileItemImpl:
433        instance_id: typing.Optional[int] = None
434        if raw_instance_id := payload.get("itemInstanceId"):
435            instance_id = int(raw_instance_id)
436
437        version_number: typing.Optional[int] = None
438        if raw_version := payload.get("versionNumber"):
439            version_number = int(raw_version)
440
441        transfer_status = enums.TransferStatus(payload["transferStatus"])
442
443        return profile.ProfileItemImpl(
444            net=self._net,
445            hash=payload["itemHash"],
446            quantity=payload["quantity"],
447            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
448            location=enums.ItemLocation(payload["location"]),
449            bucket=payload["bucketHash"],
450            transfer_status=transfer_status,
451            lockable=payload["lockable"],
452            state=enums.ItemState(payload["state"]),
453            dismantel_permissions=payload["dismantlePermission"],
454            is_wrapper=payload["isWrapper"],
455            instance_id=instance_id,
456            version_number=version_number,
457            ornament_id=payload.get("overrideStyleItemHash"),
458        )

Deserialize a JSON payload of a singular profile component item.

Parameters
Returns
def deserialize_objectives( self, payload: dict[str, typing.Any]) -> aiobungie.crates.records.Objective:
460    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
461        return records.Objective(
462            net=self._net,
463            hash=payload["objectiveHash"],
464            visible=payload["visible"],
465            complete=payload["complete"],
466            completion_value=payload["completionValue"],
467            progress=payload.get("progress"),
468            destination_hash=payload.get("destinationHash"),
469            activity_hash=payload.get("activityHash"),
470        )

Deserialize a JSON payload of an objective found in a record profile component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
  • aiobungie.crates.records.Objective: A record objective object.
def deserialize_records( self, payload: dict[str, typing.Any], scores: Optional[aiobungie.crates.records.RecordScores] = None, **nodes: int) -> aiobungie.crates.records.Record:
472    def deserialize_records(
473        self,
474        payload: typedefs.JSONObject,
475        scores: typing.Optional[records.RecordScores] = None,
476        **nodes: int,
477    ) -> records.Record:
478        objectives: typing.Optional[list[records.Objective]] = None
479        interval_objectives: typing.Optional[list[records.Objective]] = None
480        record_state: typedefs.IntAnd[records.RecordState]
481
482        record_state = records.RecordState(payload["state"])
483
484        if raw_objs := payload.get("objectives"):
485            objectives = [self.deserialize_objectives(obj) for obj in raw_objs]
486
487        if raw_interval_objs := payload.get("intervalObjectives"):
488            interval_objectives = [
489                self.deserialize_objectives(obj) for obj in raw_interval_objs
490            ]
491
492        return records.Record(
493            scores=scores,
494            categories_node_hash=nodes.get("categories_hash", undefined.UNDEFINED),
495            seals_node_hash=nodes.get("seals_hash", undefined.UNDEFINED),
496            state=record_state,
497            objectives=objectives,
498            interval_objectives=interval_objectives,
499            redeemed_count=payload.get("intervalsRedeemedCount", 0),
500            completion_times=payload.get("completedCount", None),
501            reward_visibility=payload.get("rewardVisibilty", None),
502        )

Deserialize a JSON object of a profile record component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
  • scores (typing.Optional[records.RecordScores]): The records scores object. This exists only to keep the signature of aiobungie.crates.CharacterRecord with the record object. As it will always be None in that object.
  • **nodes (int): An int kwargs use to grab the node hashes while deserializing components.
Returns
  • aiobungie.records.Record: A standard implementation of a profile record component.
def deserialize_character_records( self, payload: dict[str, typing.Any], scores: Optional[aiobungie.crates.records.RecordScores] = None, record_hashes: Optional[list[int]] = None) -> aiobungie.crates.records.CharacterRecord:
504    def deserialize_character_records(
505        self,
506        payload: typedefs.JSONObject,
507        scores: typing.Optional[records.RecordScores] = None,
508        record_hashes: typing.Optional[list[int]] = None,
509    ) -> records.CharacterRecord:
510        record = self.deserialize_records(payload, scores)
511        return records.CharacterRecord(
512            scores=scores,
513            categories_node_hash=record.categories_node_hash,
514            seals_node_hash=record.seals_node_hash,
515            state=record.state,
516            objectives=record.objectives,
517            interval_objectives=record.interval_objectives,
518            redeemed_count=payload.get("intervalsRedeemedCount", 0),
519            completion_times=payload.get("completedCount"),
520            reward_visibility=payload.get("rewardVisibilty"),
521            record_hashes=record_hashes or [],
522        )

Deserialize a JSON object of a profile character record component.

This almost does the same this as deserialize_records but has more fields which can only be found in a character record.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
  • aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
def deserialize_character_dye(self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.Dye:
524    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
525        return character.Dye(
526            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
527        )

Deserialize a JSON payload of a character's dye information.

Parameters
Returns
  • aiobungie.crates.character.Dye: Information about a character dye object.
def deserialize_character_customization( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.CustomizationOptions:
529    def deserialize_character_customization(
530        self, payload: typedefs.JSONObject
531    ) -> character.CustomizationOptions:
532        return character.CustomizationOptions(
533            personality=payload["personality"],
534            face=payload["face"],
535            skin_color=payload["skinColor"],
536            lip_color=payload["lipColor"],
537            eye_color=payload["eyeColor"],
538            hair_colors=payload.get("hairColors", []),
539            feature_colors=payload.get("featureColors", []),
540            decal_color=payload["decalColor"],
541            wear_helmet=payload["wearHelmet"],
542            hair_index=payload["hairIndex"],
543            feature_index=payload["featureIndex"],
544            decal_index=payload["decalIndex"],
545        )

Deserialize a JSON payload of a character customization information found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
def deserialize_character_minimal_equipments( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.MinimalEquipments:
547    def deserialize_character_minimal_equipments(
548        self, payload: typedefs.JSONObject
549    ) -> character.MinimalEquipments:
550        dyes = None
551        if raw_dyes := payload.get("dyes"):
552            if raw_dyes:
553                dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes]
554        return character.MinimalEquipments(
555            net=self._net, item_hash=payload["itemHash"], dyes=dyes
556        )

Deserialize a singular JSON peer view of equipment found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
def deserialize_character_render_data( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.character.RenderedData:
558    def deserialize_character_render_data(
559        self, payload: typedefs.JSONObject, /
560    ) -> character.RenderedData:
561        return character.RenderedData(
562            net=self._net,
563            customization=self.deserialize_character_customization(
564                payload["customization"]
565            ),
566            custom_dyes=[
567                self.deserialize_character_dye(dye)
568                for dye in payload["customDyes"]
569                if dye
570            ],
571            equipment=[
572                self.deserialize_character_minimal_equipments(equipment)
573                for equipment in payload["peerView"]["equipment"]
574            ],
575        )

Deserialize a JSON payload of a profile character render data component.

Parameters
Returns
def deserialize_available_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.AvailableActivity:
577    def deserialize_available_activity(
578        self, payload: typedefs.JSONObject
579    ) -> activity.AvailableActivity:
580        return activity.AvailableActivity(
581            hash=payload["activityHash"],
582            is_new=payload["isNew"],
583            is_completed=payload["isCompleted"],
584            is_visible=payload["isVisible"],
585            display_level=payload.get("displayLevel"),
586            recommended_light=payload.get("recommendedLight"),
587            difficulty=activity.Difficulty(payload["difficultyTier"]),
588            can_join=payload["canJoin"],
589            can_lead=payload["canLead"],
590        )

Deserialize a JSON payload of an available activities.

This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.

Parameters
Returns
def deserialize_character_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.CharacterActivity:
592    def deserialize_character_activity(
593        self, payload: typedefs.JSONObject
594    ) -> activity.CharacterActivity:
595        current_mode: typing.Optional[enums.GameMode] = None
596        if raw_current_mode := payload.get("currentActivityModeType"):
597            current_mode = enums.GameMode(raw_current_mode)
598
599        current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None
600        if raw_current_modes := payload.get("currentActivityModeTypes"):
601            current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes]
602
603        return activity.CharacterActivity(
604            date_started=time.clean_date(payload["dateActivityStarted"]),
605            current_hash=payload["currentActivityHash"],
606            current_mode_hash=payload["currentActivityModeHash"],
607            current_mode=current_mode,
608            current_mode_hashes=payload.get("currentActivityModeHashes"),
609            current_mode_types=current_mode_types,
610            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
611            last_story_hash=payload["lastCompletedStoryHash"],
612            available_activities=[
613                self.deserialize_available_activity(activity_)
614                for activity_ in payload["availableActivities"]
615            ],
616        )

Deserialize a JSON payload of character activity profile component.

Parameters
Returns
def deserialize_profile_items( self, payload: dict[str, typing.Any], /) -> list[aiobungie.crates.profile.ProfileItemImpl]:
618    def deserialize_profile_items(
619        self, payload: typedefs.JSONObject, /
620    ) -> list[profile.ProfileItemImpl]:
621        return [self.deserialize_profile_item(item) for item in payload["items"]]

Deserialize a JSON payload of profile items component information.

This may deserialize profileInventories or profileCurrencies or any other alternatives.

Parameters
Returns
def deserialize_progressions( self, payload: dict[str, typing.Any]) -> aiobungie.crates.progressions.Progression:
664    def deserialize_progressions(
665        self, payload: typedefs.JSONObject
666    ) -> progressions.Progression:
667        return progressions.Progression(
668            hash=int(payload["progressionHash"]),
669            level=int(payload["level"]),
670            cap=int(payload["levelCap"]),
671            daily_limit=int(payload["dailyLimit"]),
672            weekly_limit=int(payload["weeklyLimit"]),
673            current_progress=int(payload["currentProgress"]),
674            daily_progress=int(payload["dailyProgress"]),
675            needed=int(payload["progressToNextLevel"]),
676            next_level=int(payload["nextLevelAt"]),
677        )
def deserialize_milestone( self, payload: dict[str, typing.Any]) -> aiobungie.crates.milestones.Milestone:
764    def deserialize_milestone(
765        self, payload: typedefs.JSONObject
766    ) -> milestones.Milestone:
767        start_date: typing.Optional[datetime.datetime] = None
768        if raw_start_date := payload.get("startDate"):
769            start_date = time.clean_date(raw_start_date)
770
771        end_date: typing.Optional[datetime.datetime] = None
772        if raw_end_date := payload.get("endDate"):
773            end_date = time.clean_date(raw_end_date)
774
775        rewards: typing.Optional[
776            collections.Collection[milestones.MilestoneReward]
777        ] = None
778        if raw_rewards := payload.get("rewards"):
779            rewards = [
780                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
781            ]
782
783        activities: typing.Optional[
784            collections.Sequence[milestones.MilestoneActivity]
785        ] = None
786        if raw_activities := payload.get("activities"):
787            activities = [
788                self._deserialize_milestone_activity(active)
789                for active in raw_activities
790            ]
791
792        quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None
793        if raw_quests := payload.get("availableQuests"):
794            quests = [
795                self._deserialize_milestone_available_quest(quest)
796                for quest in raw_quests
797            ]
798
799        vendors: typing.Optional[
800            collections.Sequence[milestones.MilestoneVendor]
801        ] = None
802        if raw_vendors := payload.get("vendors"):
803            vendors = [
804                milestones.MilestoneVendor(
805                    vendor_hash=vendor["vendorHash"],
806                    preview_itemhash=vendor.get("previewItemHash"),
807                )
808                for vendor in raw_vendors
809            ]
810
811        return milestones.Milestone(
812            hash=payload["milestoneHash"],
813            start_date=start_date,
814            end_date=end_date,
815            order=payload["order"],
816            rewards=rewards,
817            available_quests=quests,
818            activities=activities,
819            vendors=vendors,
820        )
def deserialize_characters( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.Character]:
837    def deserialize_characters(
838        self, payload: typedefs.JSONObject
839    ) -> collections.Mapping[int, character.Character]:
840        return {
841            int(char_id): self._set_character_attrs(char)
842            for char_id, char in payload["data"].items()
843        }
def deserialize_character( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.Character:
845    def deserialize_character(
846        self, payload: typedefs.JSONObject
847    ) -> character.Character:
848        return self._set_character_attrs(payload)
def deserialize_character_equipments( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, collections.abc.Sequence[aiobungie.crates.profile.ProfileItemImpl]]:
850    def deserialize_character_equipments(
851        self, payload: typedefs.JSONObject
852    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
853        return {
854            int(char_id): self.deserialize_profile_items(item)
855            for char_id, item in payload["data"].items()
856        }
def deserialize_character_activities( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.activity.CharacterActivity]:
858    def deserialize_character_activities(
859        self, payload: typedefs.JSONObject
860    ) -> collections.Mapping[int, activity.CharacterActivity]:
861        return {
862            int(char_id): self.deserialize_character_activity(data)
863            for char_id, data in payload["data"].items()
864        }
def deserialize_characters_render_data( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.RenderedData]:
866    def deserialize_characters_render_data(
867        self, payload: typedefs.JSONObject
868    ) -> collections.Mapping[int, character.RenderedData]:
869        return {
870            int(char_id): self.deserialize_character_render_data(data)
871            for char_id, data in payload["data"].items()
872        }
def deserialize_character_progressions( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.CharacterProgression:
874    def deserialize_character_progressions(
875        self, payload: typedefs.JSONObject
876    ) -> character.CharacterProgression:
877        progressions_ = {
878            int(prog_id): self.deserialize_progressions(prog)
879            for prog_id, prog in payload["progressions"].items()
880        }
881
882        factions = {
883            int(faction_id): self._deserialize_factions(faction)
884            for faction_id, faction in payload["factions"].items()
885        }
886
887        milestones_ = {
888            int(milestone_hash): self.deserialize_milestone(milestone)
889            for milestone_hash, milestone in payload["milestones"].items()
890        }
891
892        uninstanced_item_objectives = {
893            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
894            for item_hash, obj in payload["uninstancedItemObjectives"].items()
895        }
896
897        artifact = payload["seasonalArtifact"]
898        seasonal_artifact = season.CharacterScopedArtifact(
899            hash=artifact["artifactHash"],
900            points_used=artifact["pointsUsed"],
901            reset_count=artifact["resetCount"],
902            tiers=[
903                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
904            ],
905        )
906        checklists = payload["checklists"]
907
908        return character.CharacterProgression(
909            progressions=progressions_,
910            factions=factions,
911            checklists=checklists,
912            milestones=milestones_,
913            seasonal_artifact=seasonal_artifact,
914            uninstanced_item_objectives=uninstanced_item_objectives,
915        )
def deserialize_character_progressions_mapping( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.CharacterProgression]:
917    def deserialize_character_progressions_mapping(
918        self, payload: typedefs.JSONObject
919    ) -> collections.Mapping[int, character.CharacterProgression]:
920        character_progressions: collections.Mapping[
921            int, character.CharacterProgression
922        ] = {}
923        for char_id, data in payload["data"].items():
924            # A little hack to stop mypy complaining about Mapping <-> dict
925            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)  # type: ignore[index]
926        return character_progressions
def deserialize_characters_records( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.CharacterRecord]:
928    def deserialize_characters_records(
929        self,
930        payload: typedefs.JSONObject,
931    ) -> collections.Mapping[int, records.CharacterRecord]:
932        return {
933            int(rec_id): self.deserialize_character_records(
934                rec, record_hashes=payload.get("featuredRecordHashes")
935            )
936            for rec_id, rec in payload["records"].items()
937        }
def deserialize_profile_records( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.Record]:
939    def deserialize_profile_records(
940        self, payload: typedefs.JSONObject
941    ) -> collections.Mapping[int, records.Record]:
942        raw_profile_records = payload["data"]
943        scores = records.RecordScores(
944            current_score=raw_profile_records["score"],
945            legacy_score=raw_profile_records["legacyScore"],
946            lifetime_score=raw_profile_records["lifetimeScore"],
947        )
948        return {
949            int(record_id): self.deserialize_records(
950                record,
951                scores,
952                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
953                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
954            )
955            for record_id, record in raw_profile_records["records"].items()
956        }
def deserialize_craftables_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.CraftablesComponent:
 991    def deserialize_craftables_component(
 992        self, payload: typedefs.JSONObject
 993    ) -> components.CraftablesComponent:
 994        return components.CraftablesComponent(
 995            net=self._net,
 996            craftables={
 997                int(item_id): self._deserialize_craftable_item(item)
 998                for item_id, item in payload["craftables"].items()
 999                if item is not None
1000            },
1001            crafting_root_node_hash=payload["craftingRootNodeHash"],
1002        )
def deserialize_components( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.Component:
1004    def deserialize_components(  # noqa: C901 Too complex.
1005        self, payload: typedefs.JSONObject
1006    ) -> components.Component:
1007        profile_: typing.Optional[profile.Profile] = None
1008        if raw_profile := payload.get("profile"):
1009            profile_ = self.deserialize_profile(raw_profile)
1010
1011        profile_progression: typing.Optional[profile.ProfileProgression] = None
1012        if raw_profile_progression := payload.get("profileProgression"):
1013            profile_progression = self.deserialize_profile_progression(
1014                raw_profile_progression
1015            )
1016
1017        profile_currencies: typing.Optional[
1018            collections.Sequence[profile.ProfileItemImpl]
1019        ] = None
1020        if raw_profile_currencies := payload.get("profileCurrencies"):
1021            if "data" in raw_profile_currencies:
1022                profile_currencies = self.deserialize_profile_items(
1023                    raw_profile_currencies["data"]
1024                )
1025
1026        profile_inventories: typing.Optional[
1027            collections.Sequence[profile.ProfileItemImpl]
1028        ] = None
1029        if raw_profile_inventories := payload.get("profileInventory"):
1030            if "data" in raw_profile_inventories:
1031                profile_inventories = self.deserialize_profile_items(
1032                    raw_profile_inventories["data"]
1033                )
1034
1035        profile_records: typing.Optional[
1036            collections.Mapping[int, records.Record]
1037        ] = None
1038
1039        if raw_profile_records_ := payload.get("profileRecords"):
1040            profile_records = self.deserialize_profile_records(raw_profile_records_)
1041
1042        characters: typing.Optional[typing.Mapping[int, character.Character]] = None
1043        if raw_characters := payload.get("characters"):
1044            characters = self.deserialize_characters(raw_characters)
1045
1046        character_records: typing.Optional[
1047            collections.Mapping[int, records.CharacterRecord]
1048        ] = None
1049
1050        if raw_character_records := payload.get("characterRecords"):
1051            # Had to do it in two steps..
1052            to_update: typedefs.JSONObject = {}
1053            for _, data in raw_character_records["data"].items():
1054                for record_id, record in data.items():
1055                    to_update[record_id] = record
1056
1057            character_records = {
1058                int(rec_id): self.deserialize_character_records(
1059                    rec, record_hashes=to_update.get("featuredRecordHashes")
1060                )
1061                for rec_id, rec in to_update["records"].items()
1062            }
1063
1064        character_equipments: typing.Optional[
1065            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1066        ] = None
1067        if raw_character_equips := payload.get("characterEquipment"):
1068            character_equipments = self.deserialize_character_equipments(
1069                raw_character_equips
1070            )
1071
1072        character_inventories: typing.Optional[
1073            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1074        ] = None
1075        if raw_character_inventories := payload.get("characterInventories"):
1076            if "data" in raw_character_inventories:
1077                character_inventories = self.deserialize_character_equipments(
1078                    raw_character_inventories
1079                )
1080
1081        character_activities: typing.Optional[
1082            collections.Mapping[int, activity.CharacterActivity]
1083        ] = None
1084        if raw_char_acts := payload.get("characterActivities"):
1085            character_activities = self.deserialize_character_activities(raw_char_acts)
1086
1087        character_render_data: typing.Optional[
1088            collections.Mapping[int, character.RenderedData]
1089        ] = None
1090        if raw_character_render_data := payload.get("characterRenderData"):
1091            character_render_data = self.deserialize_characters_render_data(
1092                raw_character_render_data
1093            )
1094
1095        character_progressions: typing.Optional[
1096            collections.Mapping[int, character.CharacterProgression]
1097        ] = None
1098
1099        if raw_character_progressions := payload.get("characterProgressions"):
1100            character_progressions = self.deserialize_character_progressions_mapping(
1101                raw_character_progressions
1102            )
1103
1104        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1105        if raw_profile_string_vars := payload.get("profileStringVariables"):
1106            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1107
1108        character_string_vars: typing.Optional[
1109            collections.Mapping[int, collections.Mapping[int, int]]
1110        ] = None
1111        if raw_character_string_vars := payload.get("characterStringVariables"):
1112            character_string_vars = {
1113                int(char_id): data["integerValuesByHash"]
1114                for char_id, data in raw_character_string_vars["data"].items()
1115            }
1116
1117        metrics: typing.Optional[
1118            collections.Sequence[
1119                collections.Mapping[
1120                    int, tuple[bool, typing.Optional[records.Objective]]
1121                ]
1122            ]
1123        ] = None
1124        root_node_hash: typing.Optional[int] = None
1125
1126        if raw_metrics := payload.get("metrics"):
1127            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1128            metrics = [
1129                {
1130                    int(metrics_hash): (
1131                        data["invisible"],
1132                        self.deserialize_objectives(data["objectiveProgress"])
1133                        if "objectiveProgress" in data
1134                        else None,
1135                    )
1136                    for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1137                }
1138            ]
1139        transitory: typing.Optional[fireteams.FireteamParty] = None
1140        if raw_transitory := payload.get("profileTransitoryData"):
1141            if "data" in raw_transitory:
1142                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1143
1144        item_components: typing.Optional[components.ItemsComponent] = None
1145        if raw_item_components := payload.get("itemComponents"):
1146            item_components = self.deserialize_items_component(raw_item_components)
1147
1148        profile_plugsets: typing.Optional[
1149            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1150        ] = None
1151
1152        if raw_profile_plugs := payload.get("profilePlugSets"):
1153            profile_plugsets = {
1154                int(index): [self.deserialize_plug_item_state(state) for state in data]
1155                for index, data in raw_profile_plugs["data"]["plugs"].items()
1156            }
1157
1158        character_plugsets: typing.Optional[
1159            collections.Mapping[
1160                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1161            ]
1162        ] = None
1163        if raw_char_plugsets := payload.get("characterPlugSets"):
1164            character_plugsets = {
1165                int(char_id): {
1166                    int(index): [
1167                        self.deserialize_plug_item_state(state) for state in data
1168                    ]
1169                    for index, data in inner["plugs"].items()
1170                }
1171                for char_id, inner in raw_char_plugsets["data"].items()
1172            }
1173
1174        character_collectibles: typing.Optional[
1175            collections.Mapping[int, items.Collectible]
1176        ] = None
1177        if raw_character_collectibles := payload.get("characterCollectibles"):
1178            character_collectibles = {
1179                int(char_id): self._deserialize_collectible(data)
1180                for char_id, data in raw_character_collectibles["data"].items()
1181            }
1182
1183        profile_collectibles: typing.Optional[items.Collectible] = None
1184        if raw_profile_collectibles := payload.get("profileCollectibles"):
1185            profile_collectibles = self._deserialize_collectible(
1186                raw_profile_collectibles["data"]
1187            )
1188
1189        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1190        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1191            profile_nodes = {
1192                int(node_hash): self._deserialize_node(node)
1193                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1194            }
1195
1196        character_nodes: typing.Optional[
1197            collections.Mapping[int, collections.Mapping[int, records.Node]]
1198        ] = None
1199        if raw_character_nodes := payload.get("characterPresentationNodes"):
1200            character_nodes = {
1201                int(char_id): {
1202                    int(node_hash): self._deserialize_node(node)
1203                    for node_hash, node in each_character["nodes"].items()
1204                }
1205                for char_id, each_character in raw_character_nodes["data"].items()
1206            }
1207
1208        platform_silver: typing.Optional[
1209            collections.Mapping[str, profile.ProfileItemImpl]
1210        ] = None
1211        if raw_platform_silver := payload.get("platformSilver"):
1212            if "data" in raw_platform_silver:
1213                platform_silver = {
1214                    platform_name: self.deserialize_profile_item(item)
1215                    for platform_name, item in raw_platform_silver["data"][
1216                        "platformSilver"
1217                    ].items()
1218                }
1219
1220        character_currency_lookups: typing.Optional[
1221            collections.Mapping[int, collections.Sequence[items.Currency]]
1222        ] = None
1223        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1224            if "data" in raw_char_lookups:
1225                character_currency_lookups = {
1226                    int(char_id): self._deserialize_currencies(currencie)
1227                    for char_id, currencie in raw_char_lookups["data"].items()
1228                }
1229
1230        character_craftables: typing.Optional[
1231            collections.Mapping[int, components.CraftablesComponent]
1232        ] = None
1233        if raw_character_craftables := payload.get("characterCraftables"):
1234            if "data" in raw_character_craftables:
1235                character_craftables = {
1236                    int(char_id): self.deserialize_craftables_component(craftable)
1237                    for char_id, craftable in raw_character_craftables["data"].items()
1238                }
1239
1240        return components.Component(
1241            profiles=profile_,
1242            profile_progression=profile_progression,
1243            profile_currencies=profile_currencies,
1244            profile_inventories=profile_inventories,
1245            profile_records=profile_records,
1246            characters=characters,
1247            character_records=character_records,
1248            character_equipments=character_equipments,
1249            character_inventories=character_inventories,
1250            character_activities=character_activities,
1251            character_render_data=character_render_data,
1252            character_progressions=character_progressions,
1253            profile_string_variables=profile_string_vars,
1254            character_string_variables=character_string_vars,
1255            metrics=metrics,
1256            root_node_hash=root_node_hash,
1257            transitory=transitory,
1258            item_components=item_components,
1259            profile_plugsets=profile_plugsets,
1260            character_plugsets=character_plugsets,
1261            character_collectibles=character_collectibles,
1262            profile_collectibles=profile_collectibles,
1263            profile_nodes=profile_nodes,
1264            character_nodes=character_nodes,
1265            platform_silver=platform_silver,
1266            character_currency_lookups=character_currency_lookups,
1267            character_craftables=character_craftables,
1268        )

Deserialize a JSON payload of Bungie.net profile components information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_items_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.ItemsComponent:
1270    def deserialize_items_component(
1271        self, payload: typedefs.JSONObject
1272    ) -> components.ItemsComponent:
1273        instances: typing.Optional[
1274            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1275        ] = None
1276        if raw_instances := payload.get("instances"):
1277            instances = [
1278                {
1279                    int(ins_id): self.deserialize_instanced_item(item)
1280                    for ins_id, item in raw_instances["data"].items()
1281                }
1282            ]
1283
1284        render_data: typing.Optional[
1285            collections.Mapping[int, tuple[bool, dict[int, int]]]
1286        ] = None
1287        if raw_render_data := payload.get("renderData"):
1288            render_data = {
1289                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1290                for ins_id, data in raw_render_data["data"].items()
1291            }
1292
1293        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1294        if raw_stats := payload.get("stats"):
1295            builder: collections.Mapping[int, items.ItemStatsView] = {}
1296            for ins_id, stat in raw_stats["data"].items():
1297                for _, items_ in stat.items():
1298                    builder[int(ins_id)] = self.deserialize_item_stats_view(items_)  # type: ignore[index]
1299            stats = builder
1300
1301        sockets: typing.Optional[
1302            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1303        ] = None
1304        if raw_sockets := payload.get("sockets"):
1305            sockets = {
1306                int(ins_id): [
1307                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1308                ]
1309                for ins_id, item in raw_sockets["data"].items()
1310            }
1311
1312        objeectives: typing.Optional[
1313            collections.Mapping[int, collections.Sequence[records.Objective]]
1314        ] = None
1315        if raw_objectives := payload.get("objectives"):
1316            objeectives = {
1317                int(ins_id): [self.deserialize_objectives(objective)]
1318                for ins_id, data in raw_objectives["data"].items()
1319                for objective in data["objectives"]
1320            }
1321
1322        perks: typing.Optional[
1323            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1324        ] = None
1325        if raw_perks := payload.get("perks"):
1326            perks = {
1327                int(ins_id): [
1328                    self.deserialize_item_perk(perk) for perk in item["perks"]
1329                ]
1330                for ins_id, item in raw_perks["data"].items()
1331            }
1332
1333        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1334        if raw_plug_states := payload.get("plugStates"):
1335            pending_states: list[items.PlugItemState] = []
1336            for _, plug in raw_plug_states["data"].items():
1337                pending_states.append(self.deserialize_plug_item_state(plug))
1338            plug_states = pending_states
1339
1340        reusable_plugs: typing.Optional[
1341            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1342        ] = None
1343        if raw_re_plugs := payload.get("reusablePlugs"):
1344            reusable_plugs = {
1345                int(ins_id): [
1346                    self.deserialize_plug_item_state(state) for state in inner
1347                ]
1348                for ins_id, plug in raw_re_plugs["data"].items()
1349                for inner in list(plug["plugs"].values())
1350            }
1351
1352        plug_objectives: typing.Optional[
1353            collections.Mapping[
1354                int, collections.Mapping[int, collections.Collection[records.Objective]]
1355            ]
1356        ] = None
1357        if raw_plug_objectives := payload.get("plugObjectives"):
1358            plug_objectives = {
1359                int(ins_id): {
1360                    int(obj_hash): [self.deserialize_objectives(obj) for obj in objs]
1361                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1362                }
1363                for ins_id, inner in raw_plug_objectives["data"].items()
1364            }
1365
1366        return components.ItemsComponent(
1367            sockets=sockets,
1368            stats=stats,
1369            render_data=render_data,
1370            instances=instances,
1371            objectives=objeectives,
1372            perks=perks,
1373            plug_states=plug_states,
1374            reusable_plugs=reusable_plugs,
1375            plug_objectives=plug_objectives,
1376        )

Deserialize a JSON objects within the itemComponents key.`

def deserialize_character_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.CharacterComponent:
1378    def deserialize_character_component(  # type: ignore[call-arg]
1379        self, payload: typedefs.JSONObject
1380    ) -> components.CharacterComponent:
1381        character_: typing.Optional[character.Character] = None
1382        if raw_singuler_character := payload.get("character"):
1383            character_ = self.deserialize_character(raw_singuler_character["data"])
1384
1385        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1386        if raw_inventory := payload.get("inventory"):
1387            if "data" in raw_inventory:
1388                inventory = self.deserialize_profile_items(raw_inventory["data"])
1389
1390        activities: typing.Optional[activity.CharacterActivity] = None
1391        if raw_activities := payload.get("activities"):
1392            activities = self.deserialize_character_activity(raw_activities["data"])
1393
1394        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1395        if raw_equipments := payload.get("equipment"):
1396            equipment = self.deserialize_profile_items(raw_equipments["data"])
1397
1398        progressions_: typing.Optional[character.CharacterProgression] = None
1399        if raw_progressions := payload.get("progressions"):
1400            progressions_ = self.deserialize_character_progressions(
1401                raw_progressions["data"]
1402            )
1403
1404        render_data: typing.Optional[character.RenderedData] = None
1405        if raw_render_data := payload.get("renderData"):
1406            render_data = self.deserialize_character_render_data(
1407                raw_render_data["data"]
1408            )
1409
1410        character_records: typing.Optional[
1411            collections.Mapping[int, records.CharacterRecord]
1412        ] = None
1413        if raw_char_records := payload.get("records"):
1414            character_records = self.deserialize_characters_records(
1415                raw_char_records["data"]
1416            )
1417
1418        item_components: typing.Optional[components.ItemsComponent] = None
1419        if raw_item_components := payload.get("itemComponents"):
1420            item_components = self.deserialize_items_component(raw_item_components)
1421
1422        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1423        if raw_nodes := payload.get("presentationNodes"):
1424            nodes = {
1425                int(node_hash): self._deserialize_node(node)
1426                for node_hash, node in raw_nodes["data"]["nodes"].items()
1427            }
1428
1429        collectibles: typing.Optional[items.Collectible] = None
1430        if raw_collectibles := payload.get("collectibles"):
1431            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1432
1433        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1434        if raw_currencies := payload.get("currencyLookups"):
1435            if "data" in raw_currencies:
1436                currency_lookups = self._deserialize_currencies(raw_currencies)
1437
1438        return components.CharacterComponent(
1439            activities=activities,
1440            equipment=equipment,
1441            inventory=inventory,
1442            progressions=progressions_,
1443            render_data=render_data,
1444            character=character_,
1445            character_records=character_records,
1446            profile_records=None,
1447            item_components=item_components,
1448            currency_lookups=currency_lookups,
1449            collectibles=collectibles,
1450            nodes=nodes,
1451        )

Deserialize a JSON payload of Destiny 2 character component.

Parameters
Returns
def deserialize_inventory_results( self, payload: dict[str, typing.Any]) -> Iterator[aiobungie.crates.entity.SearchableEntity]:
1478    def deserialize_inventory_results(
1479        self, payload: typedefs.JSONObject
1480    ) -> iterators.Iterator[entity.SearchableEntity]:
1481        suggested_words: list[str] = payload["suggestedWords"]
1482
1483        def _check_unknown(s: str) -> undefined.UndefinedOr[str]:
1484            return s if not typedefs.is_unknown(s) else undefined.UNDEFINED
1485
1486        return iterators.Iterator(
1487            [
1488                entity.SearchableEntity(
1489                    net=self._net,
1490                    hash=data["hash"],
1491                    entity_type=data["entityType"],
1492                    weight=data["weight"],
1493                    suggested_words=suggested_words,
1494                    name=data["displayProperties"]["name"],
1495                    has_icon=data["displayProperties"]["hasIcon"],
1496                    description=_check_unknown(
1497                        data["displayProperties"]["description"]
1498                    ),
1499                    icon=assets.Image(data["displayProperties"]["icon"]),
1500                )
1501                for data in payload["results"]["results"]
1502            ]
1503        )

Deserialize results of searched Destiny2 entities.

Parameters
Returns
def deserialize_inventory_entity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.entity.InventoryEntity:
1532    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1533        self, payload: typedefs.JSONObject, /
1534    ) -> entity.InventoryEntity:
1535        props = self._set_entity_attrs(payload)
1536        objects = self._deserialize_inventory_item_objects(payload)
1537
1538        collectible_hash: typing.Optional[int] = None
1539        if raw_collectible_hash := payload.get("collectibleHash"):
1540            collectible_hash = int(raw_collectible_hash)
1541
1542        secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1543        if raw_second_icon := payload.get("secondaryIcon"):
1544            secondary_icon = assets.Image(raw_second_icon)
1545
1546        secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1547        if raw_second_overlay := payload.get("secondaryOverlay"):
1548            secondary_overlay = assets.Image(raw_second_overlay)
1549
1550        secondary_special: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1551        if raw_second_special := payload.get("secondarySpecial"):
1552            secondary_special = assets.Image(raw_second_special)
1553
1554        screenshot: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1555        if raw_screenshot := payload.get("screenshot"):
1556            screenshot = assets.Image(raw_screenshot)
1557
1558        watermark_icon: typing.Optional[assets.Image] = None
1559        if raw_watermark_icon := payload.get("iconWatermark"):
1560            watermark_icon = assets.Image(raw_watermark_icon)
1561
1562        watermark_shelved: typing.Optional[assets.Image] = None
1563        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1564            watermark_shelved = assets.Image(raw_watermark_shelved)
1565
1566        about: undefined.UndefinedOr[str] = undefined.UNDEFINED
1567        if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown(
1568            raw_about
1569        ):
1570            about = raw_about
1571
1572        ui_item_style: undefined.UndefinedOr[str] = undefined.UNDEFINED
1573        if (
1574            raw_ui_style := payload.get("uiItemDisplayStyle")
1575        ) and not typedefs.is_unknown(raw_ui_style):
1576            ui_item_style = raw_ui_style
1577
1578        tier_and_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1579        if (
1580            raw_tier_and_name := payload.get("itemTypeAndTierDisplayName")
1581        ) and not typedefs.is_unknown(raw_tier_and_name):
1582            tier_and_name = raw_tier_and_name
1583
1584        type_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1585        if (
1586            raw_type_name := payload.get("itemTypeDisplayName")
1587        ) and not typedefs.is_unknown(raw_type_name):
1588            type_name = raw_type_name
1589
1590        display_source: undefined.UndefinedOr[str] = undefined.UNDEFINED
1591        if (
1592            raw_display_source := payload.get("displaySource")
1593        ) and not typedefs.is_unknown(raw_display_source):
1594            display_source = raw_display_source
1595
1596        lorehash: typing.Optional[int] = None
1597        if raw_lore_hash := payload.get("loreHash"):
1598            lorehash = int(raw_lore_hash)
1599
1600        summary_hash: typing.Optional[int] = None
1601        if raw_summary_hash := payload.get("summaryItemHash"):
1602            summary_hash = raw_summary_hash
1603
1604        breaker_type_hash: typing.Optional[int] = None
1605        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1606            breaker_type_hash = int(raw_breaker_type_hash)
1607
1608        damage_types: typing.Optional[collections.Sequence[int]] = None
1609        if raw_damage_types := payload.get("damageTypes"):
1610            damage_types = [int(type_) for type_ in raw_damage_types]
1611
1612        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1613        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1614            damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes]
1615
1616        default_damagetype_hash: typing.Optional[int] = None
1617        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1618            default_damagetype_hash = int(raw_defaultdmg_hash)
1619
1620        emblem_objective_hash: typing.Optional[int] = None
1621        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1622            emblem_objective_hash = int(raw_emblem_obj_hash)
1623
1624        tier_type: typing.Optional[enums.TierType] = None
1625        tier: typing.Optional[enums.ItemTier] = None
1626        bucket_hash: typing.Optional[int] = None
1627        recovery_hash: typing.Optional[int] = None
1628        tier_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1629        isinstance_item: bool = False
1630        expire_tool_tip: undefined.UndefinedOr[str] = undefined.UNDEFINED
1631        expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.UNDEFINED
1632        suppress_expiration: bool = False
1633        max_stack_size: typing.Optional[int] = None
1634        stack_label: undefined.UndefinedOr[str] = undefined.UNDEFINED
1635
1636        if inventory := payload.get("inventory"):
1637            tier_type = enums.TierType(int(inventory["tierType"]))
1638            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1639            bucket_hash = int(inventory["bucketTypeHash"])
1640            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1641            tier_name = inventory["tierTypeName"]
1642            isinstance_item = inventory["isInstanceItem"]
1643            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1644            max_stack_size = int(inventory["maxStackSize"])
1645
1646            try:
1647                stack_label = inventory["stackUniqueLabel"]
1648            except KeyError:
1649                pass
1650
1651        return entity.InventoryEntity(
1652            net=self._net,
1653            collectible_hash=collectible_hash,
1654            name=props.name,
1655            about=about,
1656            emblem_objective_hash=emblem_objective_hash,
1657            suppress_expiration=suppress_expiration,
1658            max_stack_size=max_stack_size,
1659            stack_label=stack_label,
1660            tier=tier,
1661            tier_type=tier_type,
1662            tier_name=tier_name,
1663            bucket_hash=bucket_hash,
1664            recovery_bucket_hash=recovery_hash,
1665            isinstance_item=isinstance_item,
1666            expire_in_orbit_message=expire_in_orbit_message,
1667            expiration_tooltip=expire_tool_tip,
1668            lore_hash=lorehash,
1669            type_and_tier_name=tier_and_name,
1670            summary_hash=summary_hash,
1671            ui_display_style=ui_item_style,
1672            type_name=type_name,
1673            breaker_type_hash=breaker_type_hash,
1674            description=props.description,
1675            display_source=display_source,
1676            hash=props.hash,
1677            damage_types=damage_types,
1678            index=props.index,
1679            icon=props.icon,
1680            has_icon=props.has_icon,
1681            screenshot=screenshot,
1682            watermark_icon=watermark_icon,
1683            watermark_shelved=watermark_shelved,
1684            secondary_icon=secondary_icon,
1685            secondary_overlay=secondary_overlay,
1686            secondary_special=secondary_special,
1687            type=enums.ItemType(int(payload["itemType"])),
1688            trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])],
1689            trait_ids=[trait for trait in payload.get("traitIds", [])],
1690            category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]],
1691            item_class=enums.Class(int(payload["classType"])),
1692            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1693            breaker_type=int(payload["breakerType"]),
1694            default_damagetype=int(payload["defaultDamageType"]),
1695            default_damagetype_hash=default_damagetype_hash,
1696            damagetype_hashes=damagetype_hashes,
1697            tooltip_notifications=payload["tooltipNotifications"],
1698            not_transferable=payload["nonTransferrable"],
1699            allow_actions=payload["allowActions"],
1700            is_equippable=payload["equippable"],
1701            objects=objects,
1702            background_colors=payload.get("backgroundColor", {}),
1703            season_hash=payload.get("seasonHash"),
1704            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1705        )

Deserialize a JSON payload of an inventory entity item information.

This can be any item from DestinyInventoryItemDefinition definition.

Parameters
Returns
def deserialize_objective_entity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.entity.ObjectiveEntity:
1707    def deserialize_objective_entity(
1708        self, payload: typedefs.JSONObject, /
1709    ) -> entity.ObjectiveEntity:
1710        props = self._set_entity_attrs(payload)
1711        return entity.ObjectiveEntity(
1712            net=self._net,
1713            hash=props.hash,
1714            index=props.index,
1715            description=props.description,
1716            name=props.name,
1717            has_icon=props.has_icon,
1718            icon=props.icon,
1719            unlock_value_hash=payload["unlockValueHash"],
1720            completion_value=payload["completionValue"],
1721            scope=entity.GatingScope(int(payload["scope"])),
1722            location_hash=payload["locationHash"],
1723            allowed_negative_value=payload["allowNegativeValue"],
1724            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1725            counting_downward=payload["isCountingDownward"],
1726            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1727            progress_description=payload["progressDescription"],
1728            perks=payload["perks"],
1729            stats=payload["stats"],
1730            minimum_visibility=payload["minimumVisibilityThreshold"],
1731            allow_over_completion=payload["allowOvercompletion"],
1732            show_value_style=payload["showValueOnComplete"],
1733            display_only_objective=payload["isDisplayOnlyObjective"],
1734            complete_value_style=entity.ValueUIStyle(
1735                int(payload["completedValueStyle"])
1736            ),
1737            progress_value_style=entity.ValueUIStyle(
1738                int(payload["inProgressValueStyle"])
1739            ),
1740            ui_label=payload["uiLabel"],
1741            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1742        )

Deserialize a JSON payload of an objective entity information.

Parameters
Returns
def deserialize_activity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.activity.Activity:
1770    def deserialize_activity(
1771        self,
1772        payload: typedefs.JSONObject,
1773        /,
1774    ) -> activity.Activity:
1775        period = time.clean_date(payload["period"])
1776        details = payload["activityDetails"]
1777        ref_id = int(details["referenceId"])
1778        instance_id = int(details["instanceId"])
1779        mode = enums.GameMode(details["mode"])
1780        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1781        is_private = details["isPrivate"]
1782        membership_type = enums.MembershipType(int(details["membershipType"]))
1783
1784        # Since we're using the same fields for post activity method
1785        # this check is required since post activity doesn't values values
1786        values = self._deserialize_activity_values(payload["values"])
1787
1788        return activity.Activity(
1789            net=self._net,
1790            hash=ref_id,
1791            instance_id=instance_id,
1792            mode=mode,
1793            modes=modes,
1794            is_private=is_private,
1795            membership_type=membership_type,
1796            occurred_at=period,
1797            values=values,
1798        )

Deserialize a JSON payload of an activity history information.

Parameters
Returns
def deserialize_activities( self, payload: dict[str, typing.Any]) -> Iterator[aiobungie.crates.activity.Activity]:
1800    def deserialize_activities(
1801        self, payload: typedefs.JSONObject
1802    ) -> iterators.Iterator[activity.Activity]:
1803        return iterators.Iterator(
1804            [
1805                self.deserialize_activity(activity_)
1806                for activity_ in payload["activities"]
1807            ]
1808        )

Deserialize a JSON payload of an array of activity history information.

Parameters
Returns
def deserialize_extended_weapon_values( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.ExtendedWeaponValues:
1810    def deserialize_extended_weapon_values(
1811        self, payload: typedefs.JSONObject
1812    ) -> activity.ExtendedWeaponValues:
1813        assists: typing.Optional[int] = None
1814        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1815            assists = raw_assists["basic"]["value"]
1816        assists_damage: typing.Optional[int] = None
1817
1818        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1819            assists_damage = raw_assists_damage["basic"]["value"]
1820
1821        return activity.ExtendedWeaponValues(
1822            reference_id=int(payload["referenceId"]),
1823            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1824            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1825                "value"
1826            ],
1827            assists=assists,
1828            assists_damage=assists_damage,
1829            precision_kills_percentage=(
1830                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1831                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1832                    "displayValue"
1833                ],
1834            ),
1835        )

Deserialize values of extended weapons JSON object.

Parameters
Returns
def deserialize_post_activity_player( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.activity.PostActivityPlayer:
1858    def deserialize_post_activity_player(
1859        self, payload: typedefs.JSONObject, /
1860    ) -> activity.PostActivityPlayer:
1861        player = payload["player"]
1862
1863        class_hash: typedefs.NoneOr[int] = None
1864        if (class_hash := player.get("classHash")) is not None:
1865            class_hash = class_hash
1866
1867        race_hash: typedefs.NoneOr[int] = None
1868        if (race_hash := player.get("raceHash")) is not None:
1869            race_hash = race_hash
1870
1871        gender_hash: typedefs.NoneOr[int] = None
1872        if (gender_hash := player.get("genderHash")) is not None:
1873            gender_hash = gender_hash
1874
1875        character_class: undefined.UndefinedOr[str] = undefined.UNDEFINED
1876        if (
1877            character_class := player.get("characterClass")
1878        ) and not typedefs.is_unknown(character_class):
1879            character_class = character_class
1880
1881        character_level: typedefs.NoneOr[int] = None
1882        if (character_level := player.get("characterLevel")) is not None:
1883            character_level = character_level
1884
1885        return activity.PostActivityPlayer(
1886            standing=int(payload["standing"]),
1887            score=int(payload["score"]["basic"]["value"]),
1888            character_id=payload["characterId"],
1889            destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]),
1890            character_class=character_class,
1891            character_level=character_level,
1892            race_hash=race_hash,
1893            gender_hash=gender_hash,
1894            class_hash=class_hash,
1895            light_level=int(player["lightLevel"]),
1896            emblem_hash=int(player["emblemHash"]),
1897            values=self._deserialize_activity_values(payload["values"]),
1898            extended_values=self._deserialize_extended_values(payload["extended"]),
1899        )

Deserialize a JSON payload of a post activity player information.

Parameters
Returns
def deserialize_post_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.PostActivity:
1911    def deserialize_post_activity(
1912        self, payload: typedefs.JSONObject
1913    ) -> activity.PostActivity:
1914        period = time.clean_date(payload["period"])
1915        details = payload["activityDetails"]
1916        ref_id = int(details["referenceId"])
1917        instance_id = int(details["instanceId"])
1918        mode = enums.GameMode(details["mode"])
1919        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1920        is_private = details["isPrivate"]
1921        membership_type = enums.MembershipType(int(details["membershipType"]))
1922        return activity.PostActivity(
1923            net=self._net,
1924            hash=ref_id,
1925            membership_type=membership_type,
1926            instance_id=instance_id,
1927            mode=mode,
1928            modes=modes,
1929            is_private=is_private,
1930            occurred_at=period,
1931            starting_phase=int(payload["startingPhaseIndex"]),
1932            players=[
1933                self.deserialize_post_activity_player(player)
1934                for player in payload["entries"]
1935            ],
1936            teams=[
1937                self._deserialize_post_activity_team(team) for team in payload["teams"]
1938            ],
1939        )

Deserialize a JSON payload of a post activity information.

Parameters
Returns
def deserialize_aggregated_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.AggregatedActivity:
1977    def deserialize_aggregated_activity(
1978        self, payload: typedefs.JSONObject
1979    ) -> activity.AggregatedActivity:
1980        return activity.AggregatedActivity(
1981            hash=int(payload["activityHash"]),
1982            values=self._deserialize_aggregated_activity_values(payload["values"]),
1983        )

Deserialize a JSON payload of an aggregated activity.

Parameters
Returns
def deserialize_aggregated_activities( self, payload: dict[str, typing.Any]) -> Iterator[aiobungie.crates.activity.AggregatedActivity]:
1985    def deserialize_aggregated_activities(
1986        self, payload: typedefs.JSONObject
1987    ) -> iterators.Iterator[activity.AggregatedActivity]:
1988        return iterators.Iterator(
1989            [
1990                self.deserialize_aggregated_activity(activity)
1991                for activity in payload["activities"]
1992            ]
1993        )

Deserialize a JSON payload of an array of aggregated activities.

Parameters
Returns
def deserialize_linked_profiles( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.LinkedProfile:
1995    def deserialize_linked_profiles(
1996        self, payload: typedefs.JSONObject
1997    ) -> profile.LinkedProfile:
1998        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
1999        error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2000        profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2001
2002        if raw_profile := payload.get("profiles"):
2003            for pfile in raw_profile:
2004                profiles_vec.append(self.deserialize_destiny_membership(pfile))
2005
2006        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
2007            for raw_error_pfile in raw_profiles_with_errors:
2008                if error_pfile := raw_error_pfile.get("infoCard"):
2009                    error_profiles_vec.append(
2010                        self.deserialize_destiny_membership(error_pfile)
2011                    )
2012
2013        return profile.LinkedProfile(
2014            net=self._net,
2015            bungie=bungie_user,
2016            profiles=profiles_vec,
2017            profiles_with_errors=error_profiles_vec,
2018        )

Deserialize a JSON payload of Bungie.net hard linked profile information.

Parameters
Returns
def deserialize_clan_banners( self, payload: dict[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
2020    def deserialize_clan_banners(
2021        self, payload: typedefs.JSONObject
2022    ) -> collections.Sequence[clans.ClanBanner]:
2023        banners_seq: typing.MutableSequence[clans.ClanBanner] = []
2024        if banners := payload.get("clanBannerDecals"):
2025            for k, v in banners.items():
2026                banner_obj = clans.ClanBanner(
2027                    id=int(k),
2028                    foreground=assets.Image(v["foregroundPath"]),
2029                    background=assets.Image(v["backgroundPath"]),
2030                )
2031                banners_seq.append(banner_obj)
2032        return banners_seq

Deserialize a JSON array of a clan banners information.

Parameters
Returns
def deserialize_public_milestone_content( self, payload: dict[str, typing.Any]) -> aiobungie.crates.milestones.MilestoneContent:
2034    def deserialize_public_milestone_content(
2035        self, payload: typedefs.JSONObject
2036    ) -> milestones.MilestoneContent:
2037        items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None
2038        if raw_categories := payload.get("itemCategories"):
2039            for item in raw_categories:
2040                title = undefined.UNDEFINED
2041                if raw_title := item.get("title"):
2042                    if raw_title != typedefs.Unknown:
2043                        title = raw_title
2044                if raw_hashes := item.get("itemHashes"):
2045                    hashes: collections.Sequence[int] = raw_hashes
2046
2047                items_categoris = milestones.MilestoneItems(title=title, hashes=hashes)
2048
2049        about = undefined.UNDEFINED
2050        if (raw_about := payload["about"]) != typedefs.Unknown:
2051            about = raw_about
2052
2053        status = undefined.UNDEFINED
2054        if (raw_status := payload["status"]) != typedefs.Unknown:
2055            status = raw_status
2056
2057        tips: typing.MutableSequence[undefined.UndefinedOr[str]] = []
2058        if raw_tips := payload.get("tips"):
2059            for raw_tip in raw_tips:
2060                if raw_tip == typedefs.Unknown:
2061                    raw_tip = undefined.UNDEFINED
2062                tips.append(raw_tip)
2063
2064        return milestones.MilestoneContent(
2065            about=about, status=status, tips=tips, items=items_categoris
2066        )

Deserialize a JSON payload of milestone content information.

Parameters
Returns
def deserialize_friend( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.friends.Friend:
2068    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2069        name = undefined.UNDEFINED
2070        if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown:
2071            name = raw_name
2072
2073        bungie_user: typedefs.NoneOr[user.BungieUser] = None
2074
2075        if raw_bungie_user := payload.get("bungieNetUser"):
2076            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2077
2078        return friends.Friend(
2079            net=self._net,
2080            id=int(payload["lastSeenAsMembershipId"]),
2081            name=name,
2082            code=payload.get("bungieGlobalDisplayNameCode"),
2083            relationship=enums.Relationship(payload["relationship"]),
2084            user=bungie_user,
2085            online_status=enums.Presence(payload["onlineStatus"]),
2086            online_title=payload["onlineTitle"],
2087            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2088        )

Deserialize a JSON payload of a Bungie friend information.

Parameters
Returns
def deserialize_friends( self, payload: dict[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
2090    def deserialize_friends(
2091        self, payload: typedefs.JSONObject
2092    ) -> collections.Sequence[friends.Friend]:
2093        mut_seq: typing.MutableSequence[friends.Friend] = []
2094        if raw_friends := payload.get("friends"):
2095            for friend in raw_friends:
2096                mut_seq.append(self.deserialize_friend(friend))
2097        return mut_seq

Deserialize a JSON sequence of Bungie friends information.

This is usually used to deserialize the incoming/outgoing friend requests.

Parameters
Returns
def deserialize_friend_requests( self, payload: dict[str, typing.Any]) -> aiobungie.crates.friends.FriendRequestView:
2099    def deserialize_friend_requests(
2100        self, payload: typedefs.JSONObject
2101    ) -> friends.FriendRequestView:
2102        incoming: typing.MutableSequence[friends.Friend] = []
2103        outgoing: typing.MutableSequence[friends.Friend] = []
2104
2105        if raw_incoming_requests := payload.get("incomingRequests"):
2106            for incoming_request in raw_incoming_requests:
2107                incoming.append(self.deserialize_friend(incoming_request))
2108
2109        if raw_outgoing_requests := payload.get("outgoingRequests"):
2110            for outgoing_request in raw_outgoing_requests:
2111                outgoing.append(self.deserialize_friend(outgoing_request))
2112
2113        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)

Deserialize a JSON sequence of Bungie friend requests information.

This is used for incoming/outgoing friend requests.

Parameters
Returns
def deserialize_fireteams( self, payload: dict[str, typing.Any]) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
2138    def deserialize_fireteams(
2139        self, payload: typedefs.JSONObject
2140    ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]:
2141        fireteams_: typing.MutableSequence[fireteams.Fireteam] = []
2142
2143        result: list[typedefs.JSONObject]
2144        if not (result := payload["results"]):
2145            return None
2146        for elem in result:
2147            fireteams_.append(
2148                self._set_fireteam_fields(
2149                    elem, total_results=int(payload["totalResults"])
2150                )
2151            )
2152        return fireteams_

Deserialize a JSON sequence of Bungie fireteams information.

Parameters
Returns
def deserialize_fireteam_destiny_users( self, payload: dict[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamUser:
2154    def deserialize_fireteam_destiny_users(
2155        self, payload: typedefs.JSONObject
2156    ) -> fireteams.FireteamUser:
2157        destiny_obj = self.deserialize_destiny_membership(payload)
2158        # We could helpers.just return a DestinyMembership object but this is
2159        # missing the fireteam display name and id fields.
2160        return fireteams.FireteamUser(
2161            net=self._net,
2162            id=destiny_obj.id,
2163            code=destiny_obj.code,
2164            icon=destiny_obj.icon,
2165            types=destiny_obj.types,
2166            type=destiny_obj.type,
2167            is_public=destiny_obj.is_public,
2168            crossave_override=destiny_obj.crossave_override,
2169            name=destiny_obj.name,
2170            last_seen_name=destiny_obj.last_seen_name,
2171            fireteam_display_name=payload["FireteamDisplayName"],
2172            fireteam_membership_id=enums.MembershipType(
2173                payload["FireteamMembershipType"]
2174            ),
2175        )

Deserialize a JSON payload of Bungie fireteam destiny users information.

Parameters
Returns
def deserialize_fireteam_members( self, payload: dict[str, typing.Any], *, alternatives: bool = False) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.FireteamMember]]:
2177    def deserialize_fireteam_members(
2178        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2179    ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]:
2180        members_: list[fireteams.FireteamMember] = []
2181        if members := payload.get("Members" if not alternatives else "Alternates"):
2182            for member in members:
2183                bungie_fields = self.deserialize_partial_bungie_user(member)
2184                members_fields = fireteams.FireteamMember(
2185                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2186                    has_microphone=member["hasMicrophone"],
2187                    character_id=int(member["characterId"]),
2188                    date_joined=time.clean_date(member["dateJoined"]),
2189                    last_platform_invite_date=time.clean_date(
2190                        member["lastPlatformInviteAttemptDate"]
2191                    ),
2192                    last_platform_invite_result=int(
2193                        member["lastPlatformInviteAttemptResult"]
2194                    ),
2195                    net=self._net,
2196                    name=bungie_fields.name,
2197                    id=bungie_fields.id,
2198                    icon=bungie_fields.icon,
2199                    is_public=bungie_fields.is_public,
2200                    crossave_override=bungie_fields.crossave_override,
2201                    types=bungie_fields.types,
2202                    type=bungie_fields.type,
2203                )
2204                members_.append(members_fields)
2205        else:
2206            return None
2207        return members_

Deserialize a JSON sequence of Bungie fireteam members information.

Parameters
  • payload (aiobungie.typedefs.JSONObject): The JSON payload.
  • alternatives (bool): If set to True, Then it will deserialize the alternatives data in the payload. If not the it will just deserialize the members data.
Returns
def deserialize_available_fireteams( self, data: dict[str, typing.Any], *, no_results: bool = False) -> Union[aiobungie.crates.fireteams.AvailableFireteam, collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]]:
2209    def deserialize_available_fireteams(
2210        self,
2211        data: typedefs.JSONObject,
2212        *,
2213        no_results: bool = False,
2214    ) -> typing.Union[
2215        fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam]
2216    ]:
2217        fireteams_: list[fireteams.AvailableFireteam] = []
2218
2219        # This needs to be used outside the results
2220        # JSON key.
2221        if no_results is True:
2222            payload = data
2223
2224        if result := payload.get("results"):
2225            for fireteam in result:
2226                found_fireteams = self._set_fireteam_fields(fireteam["Summary"])
2227                fireteams_fields = fireteams.AvailableFireteam(
2228                    id=found_fireteams.id,
2229                    group_id=found_fireteams.group_id,
2230                    platform=found_fireteams.platform,
2231                    activity_type=found_fireteams.activity_type,
2232                    is_immediate=found_fireteams.is_immediate,
2233                    is_public=found_fireteams.is_public,
2234                    is_valid=found_fireteams.is_valid,
2235                    owner_id=found_fireteams.owner_id,
2236                    player_slot_count=found_fireteams.player_slot_count,
2237                    available_player_slots=found_fireteams.available_player_slots,
2238                    available_alternate_slots=found_fireteams.available_alternate_slots,
2239                    title=found_fireteams.title,
2240                    date_created=found_fireteams.date_created,
2241                    locale=found_fireteams.locale,
2242                    last_modified=found_fireteams.last_modified,
2243                    total_results=found_fireteams.total_results,
2244                    members=self.deserialize_fireteam_members(payload),
2245                    alternatives=self.deserialize_fireteam_members(
2246                        payload, alternatives=True
2247                    ),
2248                )
2249            fireteams_.append(fireteams_fields)
2250            if no_results:
2251                return fireteams_fields
2252        return fireteams_

Deserialize a JSON payload of a sequence of/fireteam information.

Parameters
  • payload (aiobungie.typedefs.JSONObject): The JSON payload.
  • no_results (bool): Whether to deserialize the data from results in the payload or not.
Returns
  • typing.Union[aiobungie.crates.fireteams.AvailableFireteam, collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]] # noqa (E501): An available fireteam or a sequence of available fireteam.
def deserialize_fireteam_party( self, payload: dict[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamParty:
2254    def deserialize_fireteam_party(
2255        self, payload: typedefs.JSONObject
2256    ) -> fireteams.FireteamParty:
2257        last_destination_hash: typing.Optional[int] = None
2258        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2259            last_destination_hash = int(raw_dest_hash)
2260
2261        return fireteams.FireteamParty(
2262            members=[
2263                self._deserialize_fireteam_party_member(member)
2264                for member in payload["partyMembers"]
2265            ],
2266            activity=self._deserialize_fireteam_party_current_activity(
2267                payload["currentActivity"]
2268            ),
2269            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2270            last_destination_hash=last_destination_hash,
2271            tracking=payload["tracking"],
2272        )

Deserialize a JSON payload of profileTransitory component response.

Parameters
Returns
def deserialize_seasonal_artifact(self, payload: dict[str, typing.Any]) -> aiobungie.crates.season.Artifact:
2318    def deserialize_seasonal_artifact(
2319        self, payload: typedefs.JSONObject
2320    ) -> season.Artifact:
2321        if raw_artifact := payload.get("seasonalArtifact"):
2322            if points := raw_artifact.get("pointProgression"):
2323                points_prog = progressions.Progression(
2324                    hash=points["progressionHash"],
2325                    level=points["level"],
2326                    cap=points["levelCap"],
2327                    daily_limit=points["dailyLimit"],
2328                    weekly_limit=points["weeklyLimit"],
2329                    current_progress=points["currentProgress"],
2330                    daily_progress=points["dailyProgress"],
2331                    needed=points["progressToNextLevel"],
2332                    next_level=points["nextLevelAt"],
2333                )
2334
2335            if bonus := raw_artifact.get("powerBonusProgression"):
2336                power_bonus_prog = progressions.Progression(
2337                    hash=bonus["progressionHash"],
2338                    level=bonus["level"],
2339                    cap=bonus["levelCap"],
2340                    daily_limit=bonus["dailyLimit"],
2341                    weekly_limit=bonus["weeklyLimit"],
2342                    current_progress=bonus["currentProgress"],
2343                    daily_progress=bonus["dailyProgress"],
2344                    needed=bonus["progressToNextLevel"],
2345                    next_level=bonus["nextLevelAt"],
2346                )
2347            artifact = season.Artifact(
2348                net=self._net,
2349                hash=raw_artifact["artifactHash"],
2350                power_bonus=raw_artifact["powerBonus"],
2351                acquired_points=raw_artifact["pointsAcquired"],
2352                bonus=power_bonus_prog,
2353                points=points_prog,
2354            )
2355        return artifact

Deserialize a JSON payload of a Destiny 2 seasonal artifact information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_profile_progression( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.ProfileProgression:
2357    def deserialize_profile_progression(
2358        self, payload: typedefs.JSONObject
2359    ) -> profile.ProfileProgression:
2360        return profile.ProfileProgression(
2361            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2362            checklist={
2363                int(check_id): checklists
2364                for check_id, checklists in payload["data"]["checklists"].items()
2365            },
2366        )

Deserialize a JSON payload of a profile progression component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_instanced_item( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemInstance:
2368    def deserialize_instanced_item(
2369        self, payload: typedefs.JSONObject
2370    ) -> items.ItemInstance:
2371        damage_type_hash: typing.Optional[int] = None
2372        if raw_damagetype_hash := payload.get("damageTypeHash"):
2373            damage_type_hash = int(raw_damagetype_hash)
2374
2375        required_hashes: typing.Optional[collections.Collection[int]] = None
2376        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2377            required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes]
2378
2379        breaker_type: typing.Optional[items.ItemBreakerType] = None
2380        if raw_break_type := payload.get("breakerType"):
2381            breaker_type = items.ItemBreakerType(int(raw_break_type))
2382
2383        breaker_type_hash: typing.Optional[int] = None
2384        if raw_break_type_hash := payload.get("breakerTypeHash"):
2385            breaker_type_hash = int(raw_break_type_hash)
2386
2387        energy: typing.Optional[items.ItemEnergy] = None
2388        if raw_energy := payload.get("energy"):
2389            energy = self.deserialize_item_energy(raw_energy)
2390
2391        primary_stats = None
2392        if raw_primary_stats := payload.get("primaryStat"):
2393            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2394
2395        return items.ItemInstance(
2396            damage_type=enums.DamageType(int(payload["damageType"])),
2397            damage_type_hash=damage_type_hash,
2398            primary_stat=primary_stats,
2399            item_level=int(payload["itemLevel"]),
2400            quality=int(payload["quality"]),
2401            is_equipped=payload["isEquipped"],
2402            can_equip=payload["canEquip"],
2403            equip_required_level=int(payload["equipRequiredLevel"]),
2404            required_equip_unlock_hashes=required_hashes,
2405            cant_equip_reason=int(payload["cannotEquipReason"]),
2406            breaker_type=breaker_type,
2407            breaker_type_hash=breaker_type_hash,
2408            energy=energy,
2409        )

Deserialize a JSON object into an instanced item.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_item_energy( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemEnergy:
2411    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2412        energy_hash: typing.Optional[int] = None
2413        if raw_energy_hash := payload.get("energyTypeHash"):
2414            energy_hash = int(raw_energy_hash)
2415
2416        return items.ItemEnergy(
2417            hash=energy_hash,
2418            type=items.ItemEnergyType(int(payload["energyType"])),
2419            capacity=int(payload["energyCapacity"]),
2420            used_energy=int(payload["energyUsed"]),
2421            unused_energy=int(payload["energyUnused"]),
2422        )
def deserialize_item_perk(self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemPerk:
2424    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2425        perk_hash: typing.Optional[int] = None
2426        if raw_perk_hash := payload.get("perkHash"):
2427            perk_hash = int(raw_perk_hash)
2428
2429        return items.ItemPerk(
2430            hash=perk_hash,
2431            icon=assets.Image(payload["iconPath"]),
2432            is_active=payload["isActive"],
2433            is_visible=payload["visible"],
2434        )
def deserialize_item_socket( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemSocket:
2436    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2437        plug_hash: typing.Optional[int] = None
2438        if raw_plug_hash := payload.get("plugHash"):
2439            plug_hash = int(raw_plug_hash)
2440
2441        enable_fail_indexes: typing.Optional[list[int]] = None
2442        if raw_indexes := payload.get("enableFailIndexes"):
2443            enable_fail_indexes = [int(index) for index in raw_indexes]
2444
2445        return items.ItemSocket(
2446            plug_hash=plug_hash,
2447            is_enabled=payload["isEnabled"],
2448            enable_fail_indexes=enable_fail_indexes,
2449            is_visible=payload.get("visible"),
2450        )
def deserialize_item_stats_view( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemStatsView:
2452    def deserialize_item_stats_view(
2453        self, payload: typedefs.JSONObject
2454    ) -> items.ItemStatsView:
2455        return items.ItemStatsView(
2456            stat_hash=payload.get("statHash"), value=payload.get("value")
2457        )
def deserialize_plug_item_state( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.PlugItemState:
2459    def deserialize_plug_item_state(
2460        self, payload: typedefs.JSONObject
2461    ) -> items.PlugItemState:
2462        item_hash: typing.Optional[int] = None
2463        if raw_item_hash := payload.get("plugItemHash"):
2464            item_hash = int(raw_item_hash)
2465
2466        insert_fail_indexes: typedefs.NoneOr[list[int]] = None
2467        if raw_fail_indexes := payload.get("insertFailIndexes"):
2468            insert_fail_indexes = [int(k) for k in raw_fail_indexes]
2469
2470        enable_fail_indexes: typedefs.NoneOr[list[int]] = None
2471        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2472            enable_fail_indexes = [int(k) for k in raw_enabled_indexes]
2473
2474        return items.PlugItemState(
2475            item_hash=item_hash,
2476            insert_fail_indexes=insert_fail_indexes,
2477            enable_fail_indexes=enable_fail_indexes,
2478            is_enabled=payload["enabled"],
2479            can_insert=payload["canInsert"],
2480        )
@typing.final
class FireteamActivity(builtins.int, aiobungie.Enum):
 67@typing.final
 68class FireteamActivity(int, enums.Enum):
 69    """An enum for the fireteam activities."""
 70
 71    ALL = 0
 72    CRUCIBLE = 2
 73    TRIALS_OF_OSIRIS = 3
 74    NIGHTFALL = 4
 75    ANY = 5
 76    GAMBIT = 6
 77    BLIND_WELL = 7
 78    NIGHTMARE_HUNTS = 12
 79    ALTARS_OF_SORROWS = 14
 80    DUNGEON = 15
 81    RAID_LW = 20
 82    RAID_GOS = 21
 83    RAID_DSC = 22
 84    EXO_CHALLENGE = 23
 85    S12_WRATHBORN = 24
 86    EMPIRE_HUNTS = 25
 87    S13_BATTLEGROUNDS = 26
 88    EXOTIC_QUEST = 27
 89    RAID_VOG = 28
 90    S14_EXPUNGE = 30
 91    S15_ASTRAL_ALIGNMENT = 31
 92    S15_SHATTERED_RELAM = 32
 93    SHATTERED_THRONE = 33
 94    PROPHECY = 34
 95    PIT_OF_HERESY = 35
 96    DOE = 36
 97    """Dares of Eternity."""
 98    DUNGEON_GOA = 37
 99    """Grasp of Avarice."""
100    VOW_OF_THE_DISCPILE = 38
101    CAMPAIGN = 39
102    WELLSPRING = 40
103    S16_BATTLEGROUNDS = 41
104    S17_NIGHTMARE_CONTAINMENT = 44
105    S17_SEVER = 45

An enum for the fireteam activities.

CRUCIBLE = <FireteamActivity.CRUCIBLE: 2>
TRIALS_OF_OSIRIS = <FireteamActivity.TRIALS_OF_OSIRIS: 3>
NIGHTFALL = <FireteamActivity.NIGHTFALL: 4>
GAMBIT = <FireteamActivity.GAMBIT: 6>
BLIND_WELL = <FireteamActivity.BLIND_WELL: 7>
NIGHTMARE_HUNTS = <FireteamActivity.NIGHTMARE_HUNTS: 12>
ALTARS_OF_SORROWS = <FireteamActivity.ALTARS_OF_SORROWS: 14>
DUNGEON = <FireteamActivity.DUNGEON: 15>
RAID_LW = <FireteamActivity.RAID_LW: 20>
RAID_GOS = <FireteamActivity.RAID_GOS: 21>
RAID_DSC = <FireteamActivity.RAID_DSC: 22>
EXO_CHALLENGE = <FireteamActivity.EXO_CHALLENGE: 23>
S12_WRATHBORN = <FireteamActivity.S12_WRATHBORN: 24>
EMPIRE_HUNTS = <FireteamActivity.EMPIRE_HUNTS: 25>
S13_BATTLEGROUNDS = <FireteamActivity.S13_BATTLEGROUNDS: 26>
EXOTIC_QUEST = <FireteamActivity.EXOTIC_QUEST: 27>
RAID_VOG = <FireteamActivity.RAID_VOG: 28>
S14_EXPUNGE = <FireteamActivity.S14_EXPUNGE: 30>
S15_ASTRAL_ALIGNMENT = <FireteamActivity.S15_ASTRAL_ALIGNMENT: 31>
S15_SHATTERED_RELAM = <FireteamActivity.S15_SHATTERED_RELAM: 32>
SHATTERED_THRONE = <FireteamActivity.SHATTERED_THRONE: 33>
PROPHECY = <FireteamActivity.PROPHECY: 34>
PIT_OF_HERESY = <FireteamActivity.PIT_OF_HERESY: 35>
DOE = <FireteamActivity.DOE: 36>

Dares of Eternity.

DUNGEON_GOA = <FireteamActivity.DUNGEON_GOA: 37>

Grasp of Avarice.

VOW_OF_THE_DISCPILE = <FireteamActivity.VOW_OF_THE_DISCPILE: 38>
CAMPAIGN = <FireteamActivity.CAMPAIGN: 39>
WELLSPRING = <FireteamActivity.WELLSPRING: 40>
S16_BATTLEGROUNDS = <FireteamActivity.S16_BATTLEGROUNDS: 41>
S17_NIGHTMARE_CONTAINMENT = <FireteamActivity.S17_NIGHTMARE_CONTAINMENT: 44>
S17_SEVER = <FireteamActivity.S17_SEVER: 45>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class FireteamDate(builtins.int, aiobungie.Enum):
131@typing.final
132class FireteamDate(int, enums.Enum):
133    """An enum for fireteam date ranges."""
134
135    ALL = 0
136    NOW = 1
137    TODAY = 2
138    TWO_DAYS = 3
139    THIS_WEEK = 4

An enum for fireteam date ranges.

ALL = <FireteamDate.ALL: 0>
NOW = <FireteamDate.NOW: 1>
TODAY = <FireteamDate.TODAY: 2>
TWO_DAYS = <FireteamDate.TWO_DAYS: 3>
THIS_WEEK = <FireteamDate.THIS_WEEK: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class FireteamLanguage(builtins.str, aiobungie.Enum):
108@typing.final
109class FireteamLanguage(str, enums.Enum):
110    """An enum for fireteams languages filters."""
111
112    ALL = ""
113    ENGLISH = "en"
114    FRENCH = "fr"
115    ESPANOL = "es"
116    DEUTSCH = "de"
117    ITALIAN = "it"
118    JAPANESE = "ja"
119    PORTUGUESE = "pt-br"
120    RUSSIAN = "ru"
121    POLISH = "pl"
122    KOREAN = "ko"
123    # ? China
124    ZH_CHT = "zh-cht"
125    ZH_CHS = "zh-chs"
126
127    def __str__(self) -> str:
128        return str(self.value)

An enum for fireteams languages filters.

ENGLISH = <FireteamLanguage.ENGLISH: en>
FRENCH = <FireteamLanguage.FRENCH: fr>
ESPANOL = <FireteamLanguage.ESPANOL: es>
DEUTSCH = <FireteamLanguage.DEUTSCH: de>
ITALIAN = <FireteamLanguage.ITALIAN: it>
JAPANESE = <FireteamLanguage.JAPANESE: ja>
PORTUGUESE = <FireteamLanguage.PORTUGUESE: pt-br>
RUSSIAN = <FireteamLanguage.RUSSIAN: ru>
POLISH = <FireteamLanguage.POLISH: pl>
KOREAN = <FireteamLanguage.KOREAN: ko>
ZH_CHT = <FireteamLanguage.ZH_CHT: zh-cht>
ZH_CHS = <FireteamLanguage.ZH_CHS: zh-chs>
Inherited Members
Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
@typing.final
class FireteamPlatform(builtins.int, aiobungie.Enum):
54@typing.final
55class FireteamPlatform(int, enums.Enum):
56    """An enum for fireteam related to bungie fireteams.
57    This is different from the normal `aiobungie.MembershipType`.
58    """
59
60    ANY = 0
61    PSN_NETWORK = 1
62    XBOX_LIVE = 2
63    STEAM = 4
64    STADIA = 5

An enum for fireteam related to bungie fireteams. This is different from the normal aiobungie.MembershipType.

PSN_NETWORK = <FireteamPlatform.PSN_NETWORK: 1>
XBOX_LIVE = <FireteamPlatform.XBOX_LIVE: 2>
STEAM = <FireteamPlatform.STEAM: 4>
STADIA = <FireteamPlatform.STADIA: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Flag(enum.Flag):
 97class Flag(__enum.Flag):
 98    """Builtin Python enum flag with extra handlings."""
 99
100    # Needs to type this here for mypy
101    _value_: int
102
103    @property
104    def name(self) -> str:  # type: ignore[override]
105        if self._name_ is None:
106            self._name_ = f"UNKNOWN {self._value_}"
107
108        return self._name_
109
110    @property
111    def value(self) -> int:  # type: ignore[override]
112        return self._value_
113
114    def __str__(self) -> str:
115        return self.name
116
117    def __repr__(self) -> str:
118        return f"<{type(self).__name__}.{self.name}: {self._value_!s}>"
119
120    def __int__(self) -> int:
121        if isinstance(self.value, _ITERABLE):
122            raise TypeError(
123                f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.",
124            )
125        return int(self.value)
126
127    def __or__(self, other: typing.Union[Flag, int]) -> Flag:
128        return self.__class__(self._value_ | int(other))
129
130    def __xor__(self, other: typing.Union[Flag, int]) -> Flag:
131        return self.__class__(self._value_ ^ int(other))
132
133    def __and__(self, other: typing.Union[Flag, int]) -> Flag:
134        return self.__class__(other & int(other))
135
136    def __invert__(self) -> Flag:
137        return self.__class__(~self._value_)
138
139    def __contains__(self, other: typing.Union[Flag, int]) -> bool:
140        return self.value & int(other) == int(other)

Builtin Python enum flag with extra handlings.

name: str

The name of the Enum member.

value: int

The value of the Enum member.

@attrs.define(auto_exc=True)
class Forbidden(aiobungie.HTTPException):
137@attrs.define(auto_exc=True)
138class Forbidden(HTTPException):
139    """Exception that's raised for when status code 403 occurs."""
140
141    http_status: http.HTTPStatus = attrs.field(
142        default=http.HTTPStatus.FORBIDDEN, init=False
143    )

Exception that's raised for when status code 403 occurs.

Forbidden( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Forbidden.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class GameMode(builtins.int, aiobungie.Enum):
269@typing.final
270class GameMode(int, Enum):
271    """An Enum for all available gamemodes in Destiny 2."""
272
273    NONE = 0
274    STORY = 2
275    STRIKE = 3
276    RAID = 4
277    ALLPVP = 5
278    PATROL = 6
279    ALLPVE = 7
280    RESERVED9 = 9
281    CONTROL = 10
282    RESERVED11 = 11
283    CLASH = 12
284    RESERVED13 = 13
285    CRIMSONDOUBLES = 15
286    NIGHTFALL = 16
287    HEROICNIGHTFALL = 17
288    ALLSTRIKES = 18
289    IRONBANNER = 19
290    RESERVED20 = 20
291    RESERVED21 = 21
292    RESERVED22 = 22
293    RESERVED24 = 24
294    ALLMAYHEM = 25
295    RESERVED26 = 26
296    RESERVED27 = 27
297    RESERVED28 = 28
298    RESERVED29 = 29
299    RESERVED30 = 30
300    SUPREMACY = 31
301    PRIVATEMATCHESALL = 32
302    SURVIVAL = 37
303    COUNTDOWN = 38
304    TRIALSOFTHENINE = 39
305    SOCIAL = 40
306    TRIALSCOUNTDOWN = 41
307    TRIALSSURVIVAL = 42
308    IRONBANNERCONTROL = 43
309    IRONBANNERCLASH = 44
310    IRONBANNERSUPREMACY = 45
311    SCOREDNIGHTFALL = 46
312    SCOREDHEROICNIGHTFALL = 47
313    RUMBLE = 48
314    ALLDOUBLES = 49
315    DOUBLES = 50
316    PRIVATEMATCHESCLASH = 51
317    PRIVATEMATCHESCONTROL = 52
318    PRIVATEMATCHESSUPREMACY = 53
319    PRIVATEMATCHESCOUNTDOWN = 54
320    PRIVATEMATCHESSURVIVAL = 55
321    PRIVATEMATCHESMAYHEM = 56
322    PRIVATEMATCHESRUMBLE = 57
323    HEROICADVENTURE = 58
324    SHOWDOWN = 59
325    LOCKDOWN = 60
326    SCORCHED = 61
327    SCORCHEDTEAM = 62
328    GAMBIT = 63
329    ALLPVECOMPETITIVE = 64
330    BREAKTHROUGH = 65
331    BLACKARMORYRUN = 66
332    SALVAGE = 67
333    IRONBANNERSALVAGE = 68
334    PVPCOMPETITIVE = 69
335    PVPQUICKPLAY = 70
336    CLASHQUICKPLAY = 71
337    CLASHCOMPETITIVE = 72
338    CONTROLQUICKPLAY = 73
339    CONTROLCOMPETITIVE = 74
340    GAMBITPRIME = 75
341    RECKONING = 76
342    MENAGERIE = 77
343    VEXOFFENSIVE = 78
344    NIGHTMAREHUNT = 79
345    ELIMINATION = 80
346    MOMENTUM = 81
347    DUNGEON = 82
348    SUNDIAL = 83
349    TRIALS_OF_OSIRIS = 84
350    DARES = 85
351    OFFENSIVE = 86
352    LOSTSECTOR = 87
353    RIFT = 88
354    ZONECONTROL = 89
355    IRONBANNERRIFT = 90

An Enum for all available gamemodes in Destiny 2.

NONE = <GameMode.NONE: 0>
STORY = <GameMode.STORY: 2>
STRIKE = <GameMode.STRIKE: 3>
RAID = <GameMode.RAID: 4>
ALLPVP = <GameMode.ALLPVP: 5>
PATROL = <GameMode.PATROL: 6>
ALLPVE = <GameMode.ALLPVE: 7>
RESERVED9 = <GameMode.RESERVED9: 9>
CONTROL = <GameMode.CONTROL: 10>
RESERVED11 = <GameMode.RESERVED11: 11>
CLASH = <GameMode.CLASH: 12>
RESERVED13 = <GameMode.RESERVED13: 13>
CRIMSONDOUBLES = <GameMode.CRIMSONDOUBLES: 15>
NIGHTFALL = <GameMode.NIGHTFALL: 16>
HEROICNIGHTFALL = <GameMode.HEROICNIGHTFALL: 17>
ALLSTRIKES = <GameMode.ALLSTRIKES: 18>
IRONBANNER = <GameMode.IRONBANNER: 19>
RESERVED20 = <GameMode.RESERVED20: 20>
RESERVED21 = <GameMode.RESERVED21: 21>
RESERVED22 = <GameMode.RESERVED22: 22>
RESERVED24 = <GameMode.RESERVED24: 24>
ALLMAYHEM = <GameMode.ALLMAYHEM: 25>
RESERVED26 = <GameMode.RESERVED26: 26>
RESERVED27 = <GameMode.RESERVED27: 27>
RESERVED28 = <GameMode.RESERVED28: 28>
RESERVED29 = <GameMode.RESERVED29: 29>
RESERVED30 = <GameMode.RESERVED30: 30>
SUPREMACY = <GameMode.SUPREMACY: 31>
PRIVATEMATCHESALL = <GameMode.PRIVATEMATCHESALL: 32>
SURVIVAL = <GameMode.SURVIVAL: 37>
COUNTDOWN = <GameMode.COUNTDOWN: 38>
TRIALSOFTHENINE = <GameMode.TRIALSOFTHENINE: 39>
SOCIAL = <GameMode.SOCIAL: 40>
TRIALSCOUNTDOWN = <GameMode.TRIALSCOUNTDOWN: 41>
TRIALSSURVIVAL = <GameMode.TRIALSSURVIVAL: 42>
IRONBANNERCONTROL = <GameMode.IRONBANNERCONTROL: 43>
IRONBANNERCLASH = <GameMode.IRONBANNERCLASH: 44>
IRONBANNERSUPREMACY = <GameMode.IRONBANNERSUPREMACY: 45>
SCOREDNIGHTFALL = <GameMode.SCOREDNIGHTFALL: 46>
SCOREDHEROICNIGHTFALL = <GameMode.SCOREDHEROICNIGHTFALL: 47>
RUMBLE = <GameMode.RUMBLE: 48>
ALLDOUBLES = <GameMode.ALLDOUBLES: 49>
DOUBLES = <GameMode.DOUBLES: 50>
PRIVATEMATCHESCLASH = <GameMode.PRIVATEMATCHESCLASH: 51>
PRIVATEMATCHESCONTROL = <GameMode.PRIVATEMATCHESCONTROL: 52>
PRIVATEMATCHESSUPREMACY = <GameMode.PRIVATEMATCHESSUPREMACY: 53>
PRIVATEMATCHESCOUNTDOWN = <GameMode.PRIVATEMATCHESCOUNTDOWN: 54>
PRIVATEMATCHESSURVIVAL = <GameMode.PRIVATEMATCHESSURVIVAL: 55>
PRIVATEMATCHESMAYHEM = <GameMode.PRIVATEMATCHESMAYHEM: 56>
PRIVATEMATCHESRUMBLE = <GameMode.PRIVATEMATCHESRUMBLE: 57>
HEROICADVENTURE = <GameMode.HEROICADVENTURE: 58>
SHOWDOWN = <GameMode.SHOWDOWN: 59>
LOCKDOWN = <GameMode.LOCKDOWN: 60>
SCORCHED = <GameMode.SCORCHED: 61>
SCORCHEDTEAM = <GameMode.SCORCHEDTEAM: 62>
GAMBIT = <GameMode.GAMBIT: 63>
ALLPVECOMPETITIVE = <GameMode.ALLPVECOMPETITIVE: 64>
BREAKTHROUGH = <GameMode.BREAKTHROUGH: 65>
BLACKARMORYRUN = <GameMode.BLACKARMORYRUN: 66>
SALVAGE = <GameMode.SALVAGE: 67>
IRONBANNERSALVAGE = <GameMode.IRONBANNERSALVAGE: 68>
PVPCOMPETITIVE = <GameMode.PVPCOMPETITIVE: 69>
PVPQUICKPLAY = <GameMode.PVPQUICKPLAY: 70>
CLASHQUICKPLAY = <GameMode.CLASHQUICKPLAY: 71>
CLASHCOMPETITIVE = <GameMode.CLASHCOMPETITIVE: 72>
CONTROLQUICKPLAY = <GameMode.CONTROLQUICKPLAY: 73>
CONTROLCOMPETITIVE = <GameMode.CONTROLCOMPETITIVE: 74>
GAMBITPRIME = <GameMode.GAMBITPRIME: 75>
RECKONING = <GameMode.RECKONING: 76>
MENAGERIE = <GameMode.MENAGERIE: 77>
VEXOFFENSIVE = <GameMode.VEXOFFENSIVE: 78>
NIGHTMAREHUNT = <GameMode.NIGHTMAREHUNT: 79>
ELIMINATION = <GameMode.ELIMINATION: 80>
MOMENTUM = <GameMode.MOMENTUM: 81>
DUNGEON = <GameMode.DUNGEON: 82>
SUNDIAL = <GameMode.SUNDIAL: 83>
TRIALS_OF_OSIRIS = <GameMode.TRIALS_OF_OSIRIS: 84>
DARES = <GameMode.DARES: 85>
OFFENSIVE = <GameMode.OFFENSIVE: 86>
LOSTSECTOR = <GameMode.LOSTSECTOR: 87>
RIFT = <GameMode.RIFT: 88>
ZONECONTROL = <GameMode.ZONECONTROL: 89>
IRONBANNERRIFT = <GameMode.IRONBANNERRIFT: 90>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class GatingScope(builtins.int, aiobungie.Enum):
58@typing.final
59class GatingScope(int, enums.Enum):
60    """An enum represents restrictive type of gating that is being performed by an entity.
61
62    This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity
63    applies to everyone equally, or to their specific Profile or Character states.
64    """
65
66    NONE = 0
67    GLOBAL = 1
68    CLAN = 2
69    PROFILE = 3
70    CHARACTER = 4
71    ITEM = 5
72    ASSUMED_WORST_CASE = 6

An enum represents restrictive type of gating that is being performed by an entity.

This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.

NONE = <GatingScope.NONE: 0>
GLOBAL = <GatingScope.GLOBAL: 1>
CLAN = <GatingScope.CLAN: 2>
PROFILE = <GatingScope.PROFILE: 3>
CHARACTER = <GatingScope.CHARACTER: 4>
ITEM = <GatingScope.ITEM: 5>
ASSUMED_WORST_CASE = <GatingScope.ASSUMED_WORST_CASE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Gender(builtins.int, aiobungie.Enum):
486@typing.final
487class Gender(int, Enum):
488    """An Enum for Destiny Genders."""
489
490    MALE = 0
491    FEMALE = 1
492    UNKNOWN = 2

An Enum for Destiny Genders.

MALE = <Gender.MALE: 0>
FEMALE = <Gender.FEMALE: 1>
UNKNOWN = <Gender.UNKNOWN: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class GroupType(builtins.int, aiobungie.Enum):
655@typing.final
656class GroupType(int, Enum):
657    """An enums for the known bungie group types."""
658
659    GENERAL = 0
660    CLAN = 1

An enums for the known bungie group types.

GENERAL = <GroupType.GENERAL: 0>
CLAN = <GroupType.CLAN: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class HTTPError(aiobungie.AiobungieError):
79@attrs.define(auto_exc=True)
80class HTTPError(AiobungieError):
81    """Base HTTP request errors exception."""
82
83    message: str
84    """The error message."""
85
86    http_status: http.HTTPStatus
87    """The response status."""

Base HTTP request errors exception.

HTTPError(message: str, http_status: http.HTTPStatus)
2def __init__(self, message, http_status):
3    self.message = message
4    self.http_status = http_status
5    BaseException.__init__(self, self.message,self.http_status)

Method generated by attrs for class HTTPError.

message: str

The error message.

http_status: http.HTTPStatus

The response status.

Inherited Members
builtins.BaseException
with_traceback
args
@attrs.define(auto_exc=True, kw_only=True)
class HTTPException(aiobungie.HTTPError):
 90@attrs.define(auto_exc=True, kw_only=True)
 91class HTTPException(HTTPError):
 92    """An in-depth HTTP exception that's raised with more information."""
 93
 94    error_code: int
 95    """The returned Bungie error status code."""
 96
 97    http_status: http.HTTPStatus
 98    """The request response http status."""
 99
100    throttle_seconds: int
101    """The Bungie response throttle seconds."""
102
103    url: typing.Optional[typedefs.StrOrURL]
104    """The URL/endpoint caused this error."""
105
106    body: typing.Any
107    """The response body."""
108
109    headers: multidict.CIMultiDictProxy[str]
110    """The response headers."""
111
112    message: str
113    """A Bungie human readable message describes the cause of the error."""
114
115    error_status: str
116    """A Bungie short error status describes the cause of the error."""
117
118    message_data: dict[str, str]
119    """A dict of string key, value that includes each cause of the error
120    to a message describes information about that error.
121    """
122
123    def __str__(self) -> str:
124        if self.message:
125            message_body = self.message
126
127        if self.error_status:
128            error_status_body = self.error_status
129
130        return (
131            f"{self.http_status.name.replace('_', '').title()} {self.http_status.value}: "
132            f"Error status: {error_status_body}, Error message: {message_body} from {self.url} "
133            f"{str(self.body)}"
134        )

An in-depth HTTP exception that's raised with more information.

HTTPException( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class HTTPException.

error_code: int

The returned Bungie error status code.

http_status: http.HTTPStatus

The request response http status.

throttle_seconds: int

The Bungie response throttle seconds.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

message: str

A Bungie human readable message describes the cause of the error.

error_status: str

A Bungie short error status describes the cause of the error.

message_data: dict[str, str]

A dict of string key, value that includes each cause of the error to a message describes information about that error.

Inherited Members
builtins.BaseException
with_traceback
args
class Image:
 71class Image:
 72    """Representation of an image/avatar/picture at Bungie.
 73
 74    Example
 75    -------
 76    ```py
 77    from aiobungie import Image
 78    img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
 79    print(img)
 80    # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
 81
 82    # Stream the image.
 83    async for chunk in img:
 84        # Byte chunks of the image.
 85        print(chunk)
 86
 87    # Save the image to a file.
 88    await img.save("file_name", "/my/path/to/save/to", "jpeg")
 89    ```
 90
 91    Parameters
 92    ----------
 93    path : `str | None`
 94        The path to the image. If `None`, the default missing image path will be used.
 95    """
 96
 97    __slots__ = ("_path",)
 98
 99    def __init__(self, path: typing.Optional[str] = None) -> None:
100        self._path = path
101
102    @property
103    def is_missing(self) -> bool:
104        return not self._path
105
106    @property
107    def url(self) -> str:
108        """The URL to the image."""
109        return self.create_url()
110
111    @staticmethod
112    def missing_path() -> str:
113        """Returns the path to the missing Bungie image."""
114        return "img/misc/missing_icon_d2.png"
115
116    def create_url(self) -> str:
117        """Creates a full URL to the image path.
118
119        Returns
120        -------
121        str
122            The URL to the image.
123        """
124        return f"{url.BASE}/{self._path if self._path else self.missing_path()}"
125
126    async def save(
127        self,
128        file_name: str,
129        path: typing.Union[pathlib.Path, str],
130        /,
131        mime_type: typing.Optional[typing.Union[MimeType, str]] = None,
132    ) -> None:
133        """Saves the image to a file.
134
135        Parameters
136        ----------
137        file_name : `str`
138            A name for the file to save the image to.
139        path : `pathlib.Path | str`
140            A path tp save the image to.
141
142        Other Parameters
143        ----------------
144        mime_type : `MimeType | str`
145            Optional MIME type of the image.
146
147        Raises
148        ------
149        `FileNotFoundError`
150            If the path provided does not exist.
151        `RuntimeError`
152            If the image could not be saved.
153        `PermissionError`
154            If the path provided is not writable or does not have write permissions.
155        """
156        if isinstance(path, pathlib.Path) and not path.exists():
157            raise FileNotFoundError(f"File does not exist: {path!r}")
158
159        if self.is_missing:
160            return
161
162        mimetype = mime_type or MimeType.PNG
163        path = pathlib.Path(path)
164
165        loop = helpers.get_or_make_loop()
166        pool = concurrent.futures.ThreadPoolExecutor()
167
168        try:
169            with pool:
170                await loop.run_in_executor(
171                    pool, _write, path, file_name, mimetype, await self.read()
172                )
173                _LOGGER.info("Saved image to %s", file_name)
174
175        except asyncio.CancelledError:
176            pass
177
178        except Exception as err:
179            raise RuntimeError("Encountered an error while saving image.") from err
180
181    async def read(self) -> bytes:
182        """Read this image bytes.
183
184        Returns
185        -------
186        `bytes`
187            The bytes of this image.
188        """
189        client_session = aiohttp.ClientSession()
190
191        try:
192            await client_session.__aenter__()
193            response = await client_session.get(self.create_url())
194
195            if 300 >= response.status >= 200:
196                reader = await response.read()
197
198        except Exception as exc:
199            raise RuntimeError(f"Failed to read image: {exc}") from None
200        finally:
201            await client_session.__aexit__(None, None, None)
202        return reader
203
204    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
205        """Iterates over the image bytes lazily.
206
207        Example
208        -------
209        import aiobungie
210
211        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
212        async for chunk in resource.iter():
213            print(chunk)
214
215        Returns
216        -------
217        `collections.AsyncGenerator[bytes, None]`
218            An async generator of the image bytes.
219        """
220
221        async for chunk in self:
222            yield chunk
223
224    def __repr__(self) -> str:
225        return f"Image(url={self.create_url()})"
226
227    def __str__(self) -> str:
228        return self.create_url()
229
230    def __aiter__(self) -> Image:
231        return self
232
233    async def __anext__(self) -> bytes:
234        return await self.read()
235
236    def __await__(self) -> collections.Generator[None, None, bytes]:
237        return self.__anext__().__await__()

Representation of an image/avatar/picture at Bungie.

Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg

# Stream the image.
async for chunk in img:
    # Byte chunks of the image.
    print(chunk)

# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
  • path (str | None): The path to the image. If None, the default missing image path will be used.
Image(path: Optional[str] = None)
 99    def __init__(self, path: typing.Optional[str] = None) -> None:
100        self._path = path
is_missing: bool
url: str

The URL to the image.

@staticmethod
def missing_path() -> str:
111    @staticmethod
112    def missing_path() -> str:
113        """Returns the path to the missing Bungie image."""
114        return "img/misc/missing_icon_d2.png"

Returns the path to the missing Bungie image.

def create_url(self) -> str:
116    def create_url(self) -> str:
117        """Creates a full URL to the image path.
118
119        Returns
120        -------
121        str
122            The URL to the image.
123        """
124        return f"{url.BASE}/{self._path if self._path else self.missing_path()}"

Creates a full URL to the image path.

Returns
  • str: The URL to the image.
async def save( self, file_name: str, path: Union[pathlib.Path, str], /, mime_type: Union[aiobungie.internal.assets.MimeType, str, NoneType] = None) -> None:
126    async def save(
127        self,
128        file_name: str,
129        path: typing.Union[pathlib.Path, str],
130        /,
131        mime_type: typing.Optional[typing.Union[MimeType, str]] = None,
132    ) -> None:
133        """Saves the image to a file.
134
135        Parameters
136        ----------
137        file_name : `str`
138            A name for the file to save the image to.
139        path : `pathlib.Path | str`
140            A path tp save the image to.
141
142        Other Parameters
143        ----------------
144        mime_type : `MimeType | str`
145            Optional MIME type of the image.
146
147        Raises
148        ------
149        `FileNotFoundError`
150            If the path provided does not exist.
151        `RuntimeError`
152            If the image could not be saved.
153        `PermissionError`
154            If the path provided is not writable or does not have write permissions.
155        """
156        if isinstance(path, pathlib.Path) and not path.exists():
157            raise FileNotFoundError(f"File does not exist: {path!r}")
158
159        if self.is_missing:
160            return
161
162        mimetype = mime_type or MimeType.PNG
163        path = pathlib.Path(path)
164
165        loop = helpers.get_or_make_loop()
166        pool = concurrent.futures.ThreadPoolExecutor()
167
168        try:
169            with pool:
170                await loop.run_in_executor(
171                    pool, _write, path, file_name, mimetype, await self.read()
172                )
173                _LOGGER.info("Saved image to %s", file_name)
174
175        except asyncio.CancelledError:
176            pass
177
178        except Exception as err:
179            raise RuntimeError("Encountered an error while saving image.") from err

Saves the image to a file.

Parameters
  • file_name (str): A name for the file to save the image to.
  • path (pathlib.Path | str): A path tp save the image to.
Other Parameters
  • mime_type (MimeType | str): Optional MIME type of the image.
Raises
  • FileNotFoundError: If the path provided does not exist.
  • RuntimeError: If the image could not be saved.
  • PermissionError: If the path provided is not writable or does not have write permissions.
async def read(self) -> bytes:
181    async def read(self) -> bytes:
182        """Read this image bytes.
183
184        Returns
185        -------
186        `bytes`
187            The bytes of this image.
188        """
189        client_session = aiohttp.ClientSession()
190
191        try:
192            await client_session.__aenter__()
193            response = await client_session.get(self.create_url())
194
195            if 300 >= response.status >= 200:
196                reader = await response.read()
197
198        except Exception as exc:
199            raise RuntimeError(f"Failed to read image: {exc}") from None
200        finally:
201            await client_session.__aexit__(None, None, None)
202        return reader

Read this image bytes.

Returns
  • bytes: The bytes of this image.
async def iter(self) -> collections.abc.AsyncGenerator[bytes, None]:
204    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
205        """Iterates over the image bytes lazily.
206
207        Example
208        -------
209        import aiobungie
210
211        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
212        async for chunk in resource.iter():
213            print(chunk)
214
215        Returns
216        -------
217        `collections.AsyncGenerator[bytes, None]`
218            An async generator of the image bytes.
219        """
220
221        async for chunk in self:
222            yield chunk

Iterates over the image bytes lazily.

Example

import aiobungie

resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)

Returns
  • collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
@attrs.define(auto_exc=True)
class InternalServerError(aiobungie.HTTPException):
243@attrs.define(auto_exc=True)
244class InternalServerError(HTTPException):
245    """Raised for 5xx internal server errors."""

Raised for 5xx internal server errors.

InternalServerError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class InternalServerError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class ItemBindStatus(builtins.int, aiobungie.Enum):
721@typing.final
722class ItemBindStatus(int, Enum):
723    """An enum for Destiny 2 items bind status."""
724
725    NOT_BOUND = 0
726    BOUND_TO_CHARACTER = 1
727    BOUND_TO_ACCOUNT = 2
728    BOUNT_TO_GUILD = 3

An enum for Destiny 2 items bind status.

NOT_BOUND = <ItemBindStatus.NOT_BOUND: 0>
BOUND_TO_CHARACTER = <ItemBindStatus.BOUND_TO_CHARACTER: 1>
BOUND_TO_ACCOUNT = <ItemBindStatus.BOUND_TO_ACCOUNT: 2>
BOUNT_TO_GUILD = <ItemBindStatus.BOUNT_TO_GUILD: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemLocation(builtins.int, aiobungie.Enum):
731@typing.final
732class ItemLocation(int, Enum):
733    """An enum for Destiny 2 items location."""
734
735    UNKNOWN = 0
736    INVENTORY = 1
737    VAULT = 2
738    VENDOR = 3
739    POSTMASTER = 4

An enum for Destiny 2 items location.

UNKNOWN = <ItemLocation.UNKNOWN: 0>
INVENTORY = <ItemLocation.INVENTORY: 1>
VAULT = <ItemLocation.VAULT: 2>
VENDOR = <ItemLocation.VENDOR: 3>
POSTMASTER = <ItemLocation.POSTMASTER: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemState(aiobungie.Flag):
756@typing.final
757class ItemState(Flag):
758    """An enum for Destiny 2 item states."""
759
760    NONE = 0
761    LOCKED = 1 << 0
762    TRACKED = 1 << 1
763    MASTERWORKED = 1 << 2
764    CRAFTED = 1 << 3
765    """If this bit is set, the item has been 'crafted' by the player."""
766    HIGHLITED_OBJECTIVE = 1 << 4
767    """If this bit is set, the item is a 'highlighted' objective."""

An enum for Destiny 2 item states.

NONE = <ItemState.NONE: 0>
LOCKED = <ItemState.LOCKED: 1>
TRACKED = <ItemState.TRACKED: 2>
MASTERWORKED = <ItemState.MASTERWORKED: 4>
CRAFTED = <ItemState.CRAFTED: 8>

If this bit is set, the item has been 'crafted' by the player.

HIGHLITED_OBJECTIVE = <ItemState.HIGHLITED_OBJECTIVE: 16>

If this bit is set, the item is a 'highlighted' objective.

Inherited Members
Flag
name
value
@typing.final
class ItemSubType(builtins.int, aiobungie.Enum):
588@typing.final
589class ItemSubType(int, Enum):
590    """An enum for Destiny 2 inventory items subtype."""
591
592    NONE = 0
593    AUTORIFLE = 6
594    SHOTGUN = 7
595    MACHINEGUN = 8
596    HANDCANNON = 9
597    ROCKETLAUNCHER = 10
598    FUSIONRIFLE = 11
599    SNIPERRIFLE = 12
600    PULSERIFLE = 13
601    SCOUTRIFLE = 14
602    SIDEARM = 17
603    SWORD = 18
604    MASK = 19
605    SHADER = 20
606    ORNAMENT = 21
607    FUSIONRIFLELINE = 22
608    GRENADELAUNCHER = 23
609    SUBMACHINEGUN = 24
610    TRACERIFLE = 25
611    HELMETARMOR = 26
612    GAUNTLETSARMOR = 27
613    CHESTARMOR = 28
614    LEGARMOR = 29
615    CLASSARMOR = 30
616    BOW = 31
617    DUMMYREPEATABLEBOUNTY = 32

An enum for Destiny 2 inventory items subtype.

NONE = <ItemSubType.NONE: 0>
AUTORIFLE = <ItemSubType.AUTORIFLE: 6>
SHOTGUN = <ItemSubType.SHOTGUN: 7>
MACHINEGUN = <ItemSubType.MACHINEGUN: 8>
HANDCANNON = <ItemSubType.HANDCANNON: 9>
ROCKETLAUNCHER = <ItemSubType.ROCKETLAUNCHER: 10>
FUSIONRIFLE = <ItemSubType.FUSIONRIFLE: 11>
SNIPERRIFLE = <ItemSubType.SNIPERRIFLE: 12>
PULSERIFLE = <ItemSubType.PULSERIFLE: 13>
SCOUTRIFLE = <ItemSubType.SCOUTRIFLE: 14>
SIDEARM = <ItemSubType.SIDEARM: 17>
SWORD = <ItemSubType.SWORD: 18>
MASK = <ItemSubType.MASK: 19>
SHADER = <ItemSubType.SHADER: 20>
ORNAMENT = <ItemSubType.ORNAMENT: 21>
FUSIONRIFLELINE = <ItemSubType.FUSIONRIFLELINE: 22>
GRENADELAUNCHER = <ItemSubType.GRENADELAUNCHER: 23>
SUBMACHINEGUN = <ItemSubType.SUBMACHINEGUN: 24>
TRACERIFLE = <ItemSubType.TRACERIFLE: 25>
HELMETARMOR = <ItemSubType.HELMETARMOR: 26>
GAUNTLETSARMOR = <ItemSubType.GAUNTLETSARMOR: 27>
CHESTARMOR = <ItemSubType.CHESTARMOR: 28>
LEGARMOR = <ItemSubType.LEGARMOR: 29>
CLASSARMOR = <ItemSubType.CLASSARMOR: 30>
BOW = <ItemSubType.BOW: 31>
DUMMYREPEATABLEBOUNTY = <ItemSubType.DUMMYREPEATABLEBOUNTY: 32>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemTier(builtins.int, aiobungie.Enum):
620@typing.final
621class ItemTier(int, Enum):
622    """An enum for a Destiny 2 item tier."""
623
624    NONE = 0
625    BASIC = 3340296461
626    COMMON = 2395677314
627    RARE = 2127292149
628    LEGENDERY = 4008398120
629    EXOTIC = 2759499571

An enum for a Destiny 2 item tier.

NONE = <ItemTier.NONE: 0>
BASIC = <ItemTier.BASIC: 3340296461>
COMMON = <ItemTier.COMMON: 2395677314>
RARE = <ItemTier.RARE: 2127292149>
LEGENDERY = <ItemTier.LEGENDERY: 4008398120>
EXOTIC = <ItemTier.EXOTIC: 2759499571>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemType(builtins.int, aiobungie.Enum):
555@typing.final
556class ItemType(int, Enum):
557    """Enums for Destiny2's item types."""
558
559    NONE = 0
560    CURRENCY = 1
561    ARMOR = 2
562    WEAPON = 3
563    MESSAGE = 7
564    ENGRAM = 8
565    CONSUMABLE = 9
566    EXCHANGEMATERIAL = 10
567    MISSIONREWARD = 11
568    QUESTSTEP = 12
569    QUESTSTEPCOMPLETE = 13
570    EMBLEM = 14
571    QUEST = 15
572    SUBCLASS = 16
573    CLANBANNER = 17
574    AURA = 18
575    MOD = 19
576    DUMMY = 20
577    SHIP = 21
578    VEHICLE = 22
579    EMOTE = 23
580    GHOST = 24
581    PACKAGE = 25
582    BOUNTY = 26
583    WRAPPER = 27
584    SEASONALARTIFACT = 28
585    FINISHER = 29

Enums for Destiny2's item types.

NONE = <ItemType.NONE: 0>
CURRENCY = <ItemType.CURRENCY: 1>
ARMOR = <ItemType.ARMOR: 2>
WEAPON = <ItemType.WEAPON: 3>
MESSAGE = <ItemType.MESSAGE: 7>
ENGRAM = <ItemType.ENGRAM: 8>
CONSUMABLE = <ItemType.CONSUMABLE: 9>
EXCHANGEMATERIAL = <ItemType.EXCHANGEMATERIAL: 10>
MISSIONREWARD = <ItemType.MISSIONREWARD: 11>
QUESTSTEP = <ItemType.QUESTSTEP: 12>
QUESTSTEPCOMPLETE = <ItemType.QUESTSTEPCOMPLETE: 13>
EMBLEM = <ItemType.EMBLEM: 14>
QUEST = <ItemType.QUEST: 15>
SUBCLASS = <ItemType.SUBCLASS: 16>
CLANBANNER = <ItemType.CLANBANNER: 17>
AURA = <ItemType.AURA: 18>
MOD = <ItemType.MOD: 19>
DUMMY = <ItemType.DUMMY: 20>
SHIP = <ItemType.SHIP: 21>
VEHICLE = <ItemType.VEHICLE: 22>
EMOTE = <ItemType.EMOTE: 23>
GHOST = <ItemType.GHOST: 24>
PACKAGE = <ItemType.PACKAGE: 25>
BOUNTY = <ItemType.BOUNTY: 26>
WRAPPER = <ItemType.WRAPPER: 27>
SEASONALARTIFACT = <ItemType.SEASONALARTIFACT: 28>
FINISHER = <ItemType.FINISHER: 29>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Iterator(typing.Generic[~Item]):
 45class Iterator(typing.Generic[Item]):
 46    """A Flat, In-Memory iterator for sequenced based data.
 47
 48    Example
 49    -------
 50    ```py
 51    iterator = Iterator([1, 2, 3])
 52
 53    # Map the results.
 54    for item in iterator.map(lambda item: item * 2):
 55        print(item)
 56    # 2
 57    # 4
 58
 59    # Indexing is also supported.
 60    print(iterator[0])
 61    # 1
 62
 63    # Normal iteration.
 64    for item in iterator:
 65        print(item)
 66    # 1
 67    # 2
 68    # 3
 69
 70    # Union two iterators.
 71    iterator2 = Iterator([4, 5, 6])
 72    final = iterator | iterator2
 73    # <Iterator([1, 2, 3, 4, 5, 6])>
 74    ```
 75
 76    Parameters
 77    ----------
 78    items: `collections.Iterable[Item]`
 79        The items to iterate over.
 80    """
 81
 82    __slots__ = ("_items",)
 83
 84    def __init__(self, items: collections.Iterable[Item]) -> None:
 85        self._items = iter(items)
 86
 87    @typing.overload
 88    def collect(self) -> list[Item]:
 89        ...
 90
 91    @typing.overload
 92    def collect(self, casting: _B) -> list[_B]:
 93        ...
 94
 95    def collect(
 96        self, casting: typing.Optional[_B] = None
 97    ) -> typing.Union[list[Item], list[_B]]:
 98        """Collects all items in the iterator into a list and cast them into an object if provided.
 99
100        Example
101        -------
102        >>> iterator = Iterator([1, 2, 3])
103        >>> iterator.collect(casting=str)
104        ["1", "2", "3"]
105
106        Parameters
107        ----------
108        casting: `T | None`
109            The type to cast the items to. If `None` is provided, the items will be returned as is.
110
111        Raises
112        ------
113        `StopIteration`
114            If no elements are left in the iterator.
115        """
116        if casting is not None:
117            return typing.cast(list[_B], list(map(casting, self._items)))
118
119        return list(self._items)
120
121    def next(self) -> Item:
122        """Returns the next item in the iterator.
123
124        Example
125        -------
126        ```py
127        iterator = Iterator(["1", "2", "3"])
128        item = iterator.next()
129        assert item == "1"
130        item = iterator.next()
131        assert item == "2"
132        ```
133
134        Raises
135        ------
136        `StopIteration`
137            If no elements are left in the iterator.
138        """
139        try:
140            return self.__next__()
141        except StopIteration:
142            self._ok()
143
144    def map(
145        self, predicate: collections.Callable[[Item], OtherItem]
146    ) -> Iterator[OtherItem]:
147        """Maps each item in the iterator to its predicated value.
148
149        Example
150        -------
151        ```py
152        iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
153        print(iterator)
154        # <Iterator([1, 2, 3])>
155        ```
156
157        Parameters
158        ----------
159        predicate: `collections.Callable[[Item], OtherItem]`
160            The function to map each item in the iterator to its predicated value.
161
162        Returns
163        -------
164        `Iterator[OtherItem]`
165            The mapped iterator.
166
167        Raises
168        ------
169        `StopIteration`
170            If no elements are left in the iterator.
171        """
172        return Iterator(map(predicate, self._items))
173
174    def take(self, n: int) -> Iterator[Item]:
175        """Take the first number of items until the number of items are yielded or
176        the end of the iterator is reached.
177
178        Example
179        -------
180        ```py
181        iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
182        print(iterator.take(2))
183        # <Iterator([GameMode.RAID, GameMode.STRIKE])>
184        ```
185
186        Parameters
187        ----------
188        n: `int`
189            The number of items to take.
190
191        Raises
192        ------
193        `StopIteration`
194            If no elements are left in the iterator.
195        """
196        return Iterator(itertools.islice(self._items, n))
197
198    def take_while(
199        self, predicate: collections.Callable[[Item], bool]
200    ) -> Iterator[Item]:
201        """Yields items from the iterator while predicate returns `True`.
202
203        Example
204        -------
205        ```py
206        iterator = Iterator([STEAM, XBOX, STADIA])
207        print(iterator.take_while(lambda platform: platform is not XBOX))
208        # <Iterator([STEAM])>
209        ```
210
211        Parameters
212        ----------
213        predicate: `collections.Callable[[Item], bool]`
214            The function to predicate each item in the iterator.
215
216        Raises
217        ------
218        `StopIteration`
219            If no elements are left in the iterator.
220        """
221        return Iterator(itertools.takewhile(predicate, self._items))
222
223    def drop_while(
224        self, predicate: collections.Callable[[Item], bool]
225    ) -> Iterator[Item]:
226        """Yields items from the iterator while predicate returns `False`.
227
228        Example
229        -------
230        ```py
231        iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
232        print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
233        # <Iterator([DestinyMembership(name="Bob")])>
234        ```
235
236        Parameters
237        ----------
238        predicate: `collections.Callable[[Item], bool]`
239            The function to predicate each item in the iterator.
240
241        Raises
242        ------
243        `StopIteration`
244            If no elements are left in the iterator.
245        """
246        return Iterator(itertools.dropwhile(predicate, self._items))
247
248    def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]:
249        """Filters the iterator to only yield items that match the predicate.
250
251        Example
252        -------
253        ```py
254        names = Iterator(["Jim", "Bob", "Mike", "Jess"])
255        print(names.filter(lambda n: n != "Jim"))
256        # <Iterator(["Bob", "Mike", "Jess"])>
257        ```
258        """
259        return Iterator(filter(predicate, self._items))
260
261    def skip(self, n: int) -> Iterator[Item]:
262        """Skips the first number of items in the iterator.
263
264        Example
265        -------
266        ```py
267        iterator = Iterator([STEAM, XBOX, STADIA])
268        print(iterator.skip(1))
269        # <Iterator([XBOX, STADIA])>
270        ```
271        """
272        return Iterator(itertools.islice(self._items, n, None))
273
274    def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]:
275        """Zips the iterator with another iterable.
276
277        Example
278        -------
279        ```py
280        iterator = Iterator([1, 3, 5])
281        other = Iterator([2, 4, 6])
282        for item, other_item in iterator.zip(other):
283            print(item, other_item)
284        # <Iterator([(1, 2), (3, 4), (5, 6)])>
285        ```
286
287        Parameters
288        ----------
289        other: `Iterator[OtherItem]`
290            The iterable to zip with.
291
292        Raises
293        ------
294        `StopIteration`
295            If no elements are left in the iterator.
296        """
297        return Iterator(zip(self._items, other))
298
299    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
300        """`True` if all items in the iterator match the predicate.
301
302        Example
303        -------
304        ```py
305        iterator = Iterator([1, 2, 3])
306        while iterator.all(lambda item: isinstance(item, int)):
307            print("Still all integers")
308            continue
309        # Still all integers
310        ```
311
312        Parameters
313        ----------
314        predicate: `collections.Callable[[Item], bool]`
315            The function to test each item in the iterator.
316
317        Raises
318        ------
319        `StopIteration`
320            If no elements are left in the iterator.
321        """
322        return all(predicate(item) for item in self)
323
324    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
325        """`True` if any items in the iterator match the predicate.
326
327        Example
328        -------
329        ```py
330        iterator = Iterator([1, 2, 3])
331        if iterator.any(lambda item: isinstance(item, int)):
332            print("At least one item is an int.")
333        # At least one item is an int.
334        ```
335
336        Parameters
337        ----------
338        predicate: `collections.Callable[[Item], bool]`
339            The function to test each item in the iterator.
340
341        Raises
342        ------
343        `StopIteration`
344            If no elements are left in the iterator.
345        """
346        return any(predicate(item) for item in self)
347
348    def sort(
349        self,
350        *,
351        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
352        reverse: bool = False,
353    ) -> Iterator[Item]:
354        """Sorts the iterator.
355
356        Example
357        -------
358        ```py
359        iterator = Iterator([3, 1, 6, 7])
360        print(iterator.sort(key=lambda item: item))
361        # <Iterator([1, 3, 6, 7])>
362        ```
363
364        Parameters
365        ----------
366        key: `collections.Callable[[Item], Any]`
367            The function to sort by.
368        reverse: `bool`
369            Whether to reverse the sort.
370
371        Raises
372        ------
373        `StopIteration`
374            If no elements are left in the iterator.
375        """
376        return Iterator(sorted(self._items, key=key, reverse=reverse))
377
378    def first(self) -> Item:
379        """Returns the first item in the iterator.
380
381        Example
382        -------
383        ```py
384        iterator = Iterator([3, 1, 6, 7])
385        print(iterator.first())
386        3
387        ```
388
389        Raises
390        ------
391        `StopIteration`
392            If no elements are left in the iterator.
393        """
394        return self.take(1).next()
395
396    def reversed(self) -> Iterator[Item]:
397        """Returns a new iterator that yields the items in the iterator in reverse order.
398
399        Example
400        -------
401        ```py
402        iterator = Iterator([3, 1, 6, 7])
403        print(iterator.reversed())
404        # <Iterator([7, 6, 1, 3])>
405        ```
406
407        Raises
408        ------
409        `StopIteration`
410            If no elements are left in the iterator.
411        """
412        return Iterator(reversed(self.collect()))
413
414    def count(self) -> int:
415        """Returns the number of items in the iterator.
416
417        Example
418        -------
419        ```py
420        iterator = Iterator([3, 1, 6, 7])
421        print(iterator.count())
422        4
423        ```
424        """
425        count = 0
426        for _ in self:
427            count += 1
428
429        return count
430
431    def union(self, other: Iterator[Item]) -> Iterator[Item]:
432        """Returns a new iterator that yields all items from both iterators.
433
434        Example
435        -------
436        ```py
437        iterator = Iterator([1, 2, 3])
438        other = Iterator([4, 5, 6])
439        print(iterator.union(other))
440        # <Iterator([1, 2, 3, 4, 5, 6])>
441        ```
442
443        Parameters
444        ----------
445        other: `Iterator[Item]`
446            The iterable to union with.
447
448        Raises
449        ------
450        `StopIteration`
451            If no elements are left in the iterator.
452        """
453        return Iterator(itertools.chain(self._items, other))
454
455    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
456        """Calls the function on each item in the iterator.
457
458        Example
459        -------
460        ```py
461        iterator = Iterator([1, 2, 3])
462        iterator.for_each(lambda item: print(item))
463        # 1
464        # 2
465        # 3
466        ```
467
468        Parameters
469        ----------
470        func: `typeshed.Callable[[Item], None]`
471            The function to call on each item in the iterator.
472        """
473        for item in self:
474            func(item)
475
476    async def async_for_each(
477        self,
478        func: collections.Callable[[Item], collections.Coroutine[None, None, None]],
479    ) -> None:
480        """Calls the async function on each item in the iterator concurrently.
481
482        Example
483        -------
484        ```py
485        async def signup(username: str) -> None:
486            async with aiohttp.request('POST', '...') as r:
487                # Actual logic.
488                ...
489
490        async def main():
491            users = aiobungie.into_iter(["user_danny", "user_jojo"])
492            await users.async_for_each(lambda username: signup(username))
493        ```
494
495        Parameters
496        ----------
497        func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]`
498            The async function to call on each item in the iterator.
499        """
500        await _helpers.awaits(*(func(item) for item in self))
501
502    def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]:
503        """Returns a new iterator that yields tuples of the index and item.
504
505        Example
506        -------
507        ```py
508        iterator = Iterator([1, 2, 3])
509        for index, item in iterator.enumerate():
510            print(index, item)
511        # 0 1
512        # 1 2
513        # 2 3
514        ```
515
516        Raises
517        ------
518        `StopIteration`
519            If no elements are left in the iterator.
520        """
521        return Iterator(enumerate(self._items, start=start))
522
523    def _ok(self) -> typing.NoReturn:
524        raise StopIteration("No more items in the iterator.") from None
525
526    def __getitem__(self, index: int) -> Item:
527        try:
528            return self.skip(index).first()
529        except IndexError:
530            self._ok()
531
532    def __or__(self, other: Iterator[Item]) -> Iterator[Item]:
533        return self.union(other)
534
535    # This is a never.
536    def __setitem__(self) -> typing.NoReturn:
537        raise TypeError(
538            f"{type(self).__name__} doesn't support item assignment."
539        ) from None
540
541    def __repr__(self) -> str:
542        return f'<{self.__class__.__name__}({", ".join([str(item) for item in self])})>'
543
544    def __len__(self) -> int:
545        return self.count()
546
547    def __iter__(self) -> Iterator[Item]:
548        return self
549
550    def __next__(self) -> Item:
551        try:
552            item = next(self._items)
553        except StopIteration:
554            self._ok()
555
556        return item

A Flat, In-Memory iterator for sequenced based data.

Example
iterator = Iterator([1, 2, 3])

# Map the results.
for item in iterator.map(lambda item: item * 2):
    print(item)
# 2
# 4

# Indexing is also supported.
print(iterator[0])
# 1

# Normal iteration.
for item in iterator:
    print(item)
# 1
# 2
# 3

# Union two iterators.
iterator2 = Iterator([4, 5, 6])
final = iterator | iterator2
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
  • items (collections.Iterable[Item]): The items to iterate over.
Iterator(items: collections.abc.Iterable[~Item])
84    def __init__(self, items: collections.Iterable[Item]) -> None:
85        self._items = iter(items)
def collect( self, casting: 'typing.Optional[_B]' = None) -> 'typing.Union[list[Item], list[_B]]':
 95    def collect(
 96        self, casting: typing.Optional[_B] = None
 97    ) -> typing.Union[list[Item], list[_B]]:
 98        """Collects all items in the iterator into a list and cast them into an object if provided.
 99
100        Example
101        -------
102        >>> iterator = Iterator([1, 2, 3])
103        >>> iterator.collect(casting=str)
104        ["1", "2", "3"]
105
106        Parameters
107        ----------
108        casting: `T | None`
109            The type to cast the items to. If `None` is provided, the items will be returned as is.
110
111        Raises
112        ------
113        `StopIteration`
114            If no elements are left in the iterator.
115        """
116        if casting is not None:
117            return typing.cast(list[_B], list(map(casting, self._items)))
118
119        return list(self._items)

Collects all items in the iterator into a list and cast them into an object if provided.

Example
>>> iterator = Iterator([1, 2, 3])
>>> iterator.collect(casting=str)
["1", "2", "3"]
Parameters
  • casting (T | None): The type to cast the items to. If None is provided, the items will be returned as is.
Raises
  • StopIteration: If no elements are left in the iterator.
def next(self) -> ~Item:
121    def next(self) -> Item:
122        """Returns the next item in the iterator.
123
124        Example
125        -------
126        ```py
127        iterator = Iterator(["1", "2", "3"])
128        item = iterator.next()
129        assert item == "1"
130        item = iterator.next()
131        assert item == "2"
132        ```
133
134        Raises
135        ------
136        `StopIteration`
137            If no elements are left in the iterator.
138        """
139        try:
140            return self.__next__()
141        except StopIteration:
142            self._ok()

Returns the next item in the iterator.

Example
iterator = Iterator(["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
  • StopIteration: If no elements are left in the iterator.
def map( self, predicate: 'collections.Callable[[Item], OtherItem]') -> 'Iterator[OtherItem]':
144    def map(
145        self, predicate: collections.Callable[[Item], OtherItem]
146    ) -> Iterator[OtherItem]:
147        """Maps each item in the iterator to its predicated value.
148
149        Example
150        -------
151        ```py
152        iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
153        print(iterator)
154        # <Iterator([1, 2, 3])>
155        ```
156
157        Parameters
158        ----------
159        predicate: `collections.Callable[[Item], OtherItem]`
160            The function to map each item in the iterator to its predicated value.
161
162        Returns
163        -------
164        `Iterator[OtherItem]`
165            The mapped iterator.
166
167        Raises
168        ------
169        `StopIteration`
170            If no elements are left in the iterator.
171        """
172        return Iterator(map(predicate, self._items))

Maps each item in the iterator to its predicated value.

Example
iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
print(iterator)
# <Iterator([1, 2, 3])>
Parameters
  • predicate (collections.Callable[[Item], OtherItem]): The function to map each item in the iterator to its predicated value.
Returns
  • Iterator[OtherItem]: The mapped iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def take(self, n: int) -> Iterator[~Item]:
174    def take(self, n: int) -> Iterator[Item]:
175        """Take the first number of items until the number of items are yielded or
176        the end of the iterator is reached.
177
178        Example
179        -------
180        ```py
181        iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
182        print(iterator.take(2))
183        # <Iterator([GameMode.RAID, GameMode.STRIKE])>
184        ```
185
186        Parameters
187        ----------
188        n: `int`
189            The number of items to take.
190
191        Raises
192        ------
193        `StopIteration`
194            If no elements are left in the iterator.
195        """
196        return Iterator(itertools.islice(self._items, n))

Take the first number of items until the number of items are yielded or the end of the iterator is reached.

Example
iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
print(iterator.take(2))
# <Iterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
  • n (int): The number of items to take.
Raises
  • StopIteration: If no elements are left in the iterator.
def take_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> Iterator[~Item]:
198    def take_while(
199        self, predicate: collections.Callable[[Item], bool]
200    ) -> Iterator[Item]:
201        """Yields items from the iterator while predicate returns `True`.
202
203        Example
204        -------
205        ```py
206        iterator = Iterator([STEAM, XBOX, STADIA])
207        print(iterator.take_while(lambda platform: platform is not XBOX))
208        # <Iterator([STEAM])>
209        ```
210
211        Parameters
212        ----------
213        predicate: `collections.Callable[[Item], bool]`
214            The function to predicate each item in the iterator.
215
216        Raises
217        ------
218        `StopIteration`
219            If no elements are left in the iterator.
220        """
221        return Iterator(itertools.takewhile(predicate, self._items))

Yields items from the iterator while predicate returns True.

Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.take_while(lambda platform: platform is not XBOX))
# <Iterator([STEAM])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def drop_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> Iterator[~Item]:
223    def drop_while(
224        self, predicate: collections.Callable[[Item], bool]
225    ) -> Iterator[Item]:
226        """Yields items from the iterator while predicate returns `False`.
227
228        Example
229        -------
230        ```py
231        iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
232        print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
233        # <Iterator([DestinyMembership(name="Bob")])>
234        ```
235
236        Parameters
237        ----------
238        predicate: `collections.Callable[[Item], bool]`
239            The function to predicate each item in the iterator.
240
241        Raises
242        ------
243        `StopIteration`
244            If no elements are left in the iterator.
245        """
246        return Iterator(itertools.dropwhile(predicate, self._items))

Yields items from the iterator while predicate returns False.

Example
iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
# <Iterator([DestinyMembership(name="Bob")])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def filter( self, predicate: collections.abc.Callable[[~Item], bool]) -> Iterator[~Item]:
248    def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]:
249        """Filters the iterator to only yield items that match the predicate.
250
251        Example
252        -------
253        ```py
254        names = Iterator(["Jim", "Bob", "Mike", "Jess"])
255        print(names.filter(lambda n: n != "Jim"))
256        # <Iterator(["Bob", "Mike", "Jess"])>
257        ```
258        """
259        return Iterator(filter(predicate, self._items))

Filters the iterator to only yield items that match the predicate.

Example
names = Iterator(["Jim", "Bob", "Mike", "Jess"])
print(names.filter(lambda n: n != "Jim"))
# <Iterator(["Bob", "Mike", "Jess"])>
def skip(self, n: int) -> Iterator[~Item]:
261    def skip(self, n: int) -> Iterator[Item]:
262        """Skips the first number of items in the iterator.
263
264        Example
265        -------
266        ```py
267        iterator = Iterator([STEAM, XBOX, STADIA])
268        print(iterator.skip(1))
269        # <Iterator([XBOX, STADIA])>
270        ```
271        """
272        return Iterator(itertools.islice(self._items, n, None))

Skips the first number of items in the iterator.

Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.skip(1))
# <Iterator([XBOX, STADIA])>
def zip(self, other: 'Iterator[OtherItem]') -> 'Iterator[tuple[Item, OtherItem]]':
274    def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]:
275        """Zips the iterator with another iterable.
276
277        Example
278        -------
279        ```py
280        iterator = Iterator([1, 3, 5])
281        other = Iterator([2, 4, 6])
282        for item, other_item in iterator.zip(other):
283            print(item, other_item)
284        # <Iterator([(1, 2), (3, 4), (5, 6)])>
285        ```
286
287        Parameters
288        ----------
289        other: `Iterator[OtherItem]`
290            The iterable to zip with.
291
292        Raises
293        ------
294        `StopIteration`
295            If no elements are left in the iterator.
296        """
297        return Iterator(zip(self._items, other))

Zips the iterator with another iterable.

Example
iterator = Iterator([1, 3, 5])
other = Iterator([2, 4, 6])
for item, other_item in iterator.zip(other):
    print(item, other_item)
# <Iterator([(1, 2), (3, 4), (5, 6)])>
Parameters
  • other (Iterator[OtherItem]): The iterable to zip with.
Raises
  • StopIteration: If no elements are left in the iterator.
def all(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
299    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
300        """`True` if all items in the iterator match the predicate.
301
302        Example
303        -------
304        ```py
305        iterator = Iterator([1, 2, 3])
306        while iterator.all(lambda item: isinstance(item, int)):
307            print("Still all integers")
308            continue
309        # Still all integers
310        ```
311
312        Parameters
313        ----------
314        predicate: `collections.Callable[[Item], bool]`
315            The function to test each item in the iterator.
316
317        Raises
318        ------
319        `StopIteration`
320            If no elements are left in the iterator.
321        """
322        return all(predicate(item) for item in self)

True if all items in the iterator match the predicate.

Example
iterator = Iterator([1, 2, 3])
while iterator.all(lambda item: isinstance(item, int)):
    print("Still all integers")
    continue
# Still all integers
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def any(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
324    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
325        """`True` if any items in the iterator match the predicate.
326
327        Example
328        -------
329        ```py
330        iterator = Iterator([1, 2, 3])
331        if iterator.any(lambda item: isinstance(item, int)):
332            print("At least one item is an int.")
333        # At least one item is an int.
334        ```
335
336        Parameters
337        ----------
338        predicate: `collections.Callable[[Item], bool]`
339            The function to test each item in the iterator.
340
341        Raises
342        ------
343        `StopIteration`
344            If no elements are left in the iterator.
345        """
346        return any(predicate(item) for item in self)

True if any items in the iterator match the predicate.

Example
iterator = Iterator([1, 2, 3])
if iterator.any(lambda item: isinstance(item, int)):
    print("At least one item is an int.")
# At least one item is an int.
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def sort( self, *, key: 'collections.Callable[[Item], typeshed.SupportsRichComparison]', reverse: bool = False) -> Iterator[~Item]:
348    def sort(
349        self,
350        *,
351        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
352        reverse: bool = False,
353    ) -> Iterator[Item]:
354        """Sorts the iterator.
355
356        Example
357        -------
358        ```py
359        iterator = Iterator([3, 1, 6, 7])
360        print(iterator.sort(key=lambda item: item))
361        # <Iterator([1, 3, 6, 7])>
362        ```
363
364        Parameters
365        ----------
366        key: `collections.Callable[[Item], Any]`
367            The function to sort by.
368        reverse: `bool`
369            Whether to reverse the sort.
370
371        Raises
372        ------
373        `StopIteration`
374            If no elements are left in the iterator.
375        """
376        return Iterator(sorted(self._items, key=key, reverse=reverse))

Sorts the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.sort(key=lambda item: item))
# <Iterator([1, 3, 6, 7])>
Parameters
  • key (collections.Callable[[Item], Any]): The function to sort by.
  • reverse (bool): Whether to reverse the sort.
Raises
  • StopIteration: If no elements are left in the iterator.
def first(self) -> ~Item:
378    def first(self) -> Item:
379        """Returns the first item in the iterator.
380
381        Example
382        -------
383        ```py
384        iterator = Iterator([3, 1, 6, 7])
385        print(iterator.first())
386        3
387        ```
388
389        Raises
390        ------
391        `StopIteration`
392            If no elements are left in the iterator.
393        """
394        return self.take(1).next()

Returns the first item in the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.first())
3
Raises
  • StopIteration: If no elements are left in the iterator.
def reversed(self) -> Iterator[~Item]:
396    def reversed(self) -> Iterator[Item]:
397        """Returns a new iterator that yields the items in the iterator in reverse order.
398
399        Example
400        -------
401        ```py
402        iterator = Iterator([3, 1, 6, 7])
403        print(iterator.reversed())
404        # <Iterator([7, 6, 1, 3])>
405        ```
406
407        Raises
408        ------
409        `StopIteration`
410            If no elements are left in the iterator.
411        """
412        return Iterator(reversed(self.collect()))

Returns a new iterator that yields the items in the iterator in reverse order.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.reversed())
# <Iterator([7, 6, 1, 3])>
Raises
  • StopIteration: If no elements are left in the iterator.
def count(self) -> int:
414    def count(self) -> int:
415        """Returns the number of items in the iterator.
416
417        Example
418        -------
419        ```py
420        iterator = Iterator([3, 1, 6, 7])
421        print(iterator.count())
422        4
423        ```
424        """
425        count = 0
426        for _ in self:
427            count += 1
428
429        return count

Returns the number of items in the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.count())
4
def union( self, other: Iterator[~Item]) -> Iterator[~Item]:
431    def union(self, other: Iterator[Item]) -> Iterator[Item]:
432        """Returns a new iterator that yields all items from both iterators.
433
434        Example
435        -------
436        ```py
437        iterator = Iterator([1, 2, 3])
438        other = Iterator([4, 5, 6])
439        print(iterator.union(other))
440        # <Iterator([1, 2, 3, 4, 5, 6])>
441        ```
442
443        Parameters
444        ----------
445        other: `Iterator[Item]`
446            The iterable to union with.
447
448        Raises
449        ------
450        `StopIteration`
451            If no elements are left in the iterator.
452        """
453        return Iterator(itertools.chain(self._items, other))

Returns a new iterator that yields all items from both iterators.

Example
iterator = Iterator([1, 2, 3])
other = Iterator([4, 5, 6])
print(iterator.union(other))
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
  • other (Iterator[Item]): The iterable to union with.
Raises
  • StopIteration: If no elements are left in the iterator.
def for_each(self, func: collections.abc.Callable[[~Item], typing.Any]) -> None:
455    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
456        """Calls the function on each item in the iterator.
457
458        Example
459        -------
460        ```py
461        iterator = Iterator([1, 2, 3])
462        iterator.for_each(lambda item: print(item))
463        # 1
464        # 2
465        # 3
466        ```
467
468        Parameters
469        ----------
470        func: `typeshed.Callable[[Item], None]`
471            The function to call on each item in the iterator.
472        """
473        for item in self:
474            func(item)

Calls the function on each item in the iterator.

Example
iterator = Iterator([1, 2, 3])
iterator.for_each(lambda item: print(item))
# 1
# 2
# 3
Parameters
  • func (typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
async def async_for_each( self, func: collections.abc.Callable[[~Item], collections.abc.Coroutine[None, None, None]]) -> None:
476    async def async_for_each(
477        self,
478        func: collections.Callable[[Item], collections.Coroutine[None, None, None]],
479    ) -> None:
480        """Calls the async function on each item in the iterator concurrently.
481
482        Example
483        -------
484        ```py
485        async def signup(username: str) -> None:
486            async with aiohttp.request('POST', '...') as r:
487                # Actual logic.
488                ...
489
490        async def main():
491            users = aiobungie.into_iter(["user_danny", "user_jojo"])
492            await users.async_for_each(lambda username: signup(username))
493        ```
494
495        Parameters
496        ----------
497        func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]`
498            The async function to call on each item in the iterator.
499        """
500        await _helpers.awaits(*(func(item) for item in self))

Calls the async function on each item in the iterator concurrently.

Example
async def signup(username: str) -> None:
    async with aiohttp.request('POST', '...') as r:
        # Actual logic.
        ...

async def main():
    users = aiobungie.into_iter(["user_danny", "user_jojo"])
    await users.async_for_each(lambda username: signup(username))
Parameters
  • func (collections.Callable[[Item], collections.Coroutine[None, None, None]]): The async function to call on each item in the iterator.
def enumerate( self, *, start: int = 0) -> Iterator[tuple[int, ~Item]]:
502    def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]:
503        """Returns a new iterator that yields tuples of the index and item.
504
505        Example
506        -------
507        ```py
508        iterator = Iterator([1, 2, 3])
509        for index, item in iterator.enumerate():
510            print(index, item)
511        # 0 1
512        # 1 2
513        # 2 3
514        ```
515
516        Raises
517        ------
518        `StopIteration`
519            If no elements are left in the iterator.
520        """
521        return Iterator(enumerate(self._items, start=start))

Returns a new iterator that yields tuples of the index and item.

Example
iterator = Iterator([1, 2, 3])
for index, item in iterator.enumerate():
    print(index, item)
# 0 1
# 1 2
# 2 3
Raises
  • StopIteration: If no elements are left in the iterator.
@typing.final
class MembershipOption(builtins.int, aiobungie.Enum):
712@typing.final
713class MembershipOption(int, Enum):
714    """A enum for GroupV2 membership options."""
715
716    REVIEWD = 0
717    OPEN = 1
718    CLOSED = 2

A enum for GroupV2 membership options.

REVIEWD = <MembershipOption.REVIEWD: 0>
OPEN = <MembershipOption.OPEN: 1>
CLOSED = <MembershipOption.CLOSED: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class MembershipType(builtins.int, aiobungie.Enum):
460@typing.final
461class MembershipType(int, Enum):
462    """An Enum for Bungie membership types."""
463
464    NONE = 0
465    XBOX = 1
466    PSN = 2
467    STEAM = 3
468    BLIZZARD = 4
469    STADIA = 5
470    EPIC_GAMES_STORE = 6
471    DEMON = 10
472    BUNGIE = 254
473    ALL = -1

An Enum for Bungie membership types.

NONE = <MembershipType.NONE: 0>
XBOX = <MembershipType.XBOX: 1>
PSN = <MembershipType.PSN: 2>
STEAM = <MembershipType.STEAM: 3>
BLIZZARD = <MembershipType.BLIZZARD: 4>
STADIA = <MembershipType.STADIA: 5>
EPIC_GAMES_STORE = <MembershipType.EPIC_GAMES_STORE: 6>
DEMON = <MembershipType.DEMON: 10>
BUNGIE = <MembershipType.BUNGIE: 254>
ALL = <MembershipType.ALL: -1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class MembershipTypeError(aiobungie.BadRequest):
182@attrs.define(auto_exc=True)
183class MembershipTypeError(BadRequest):
184    """A bad request error raised when passing wrong membership to the request.
185
186    Those fields are useful since it returns the correct membership and id which can be used
187    to make the request again with those fields.
188
189    Example
190    -------
191    ```py
192    try:
193        profile = await client.fetch_profile(
194            member_id=1,
195            type=aiobungie.MembershipType.STADIA,
196            components=[]
197        )
198
199    # Membership type is wrong!
200    except aiobungie.MembershipTypeError as err:
201        correct_membersip = err.into_membership()
202        profile_id = err.membership_id
203
204        # Recall the method.
205        profile = await client.fetch_profile(
206            member_id=profile_id,
207            type=correct_membership,
208            components=[]
209        )
210    ```
211    """
212
213    membership_type: str
214    """The errored membership type passed to the request."""
215
216    membership_id: int
217    """The errored user's membership id."""
218
219    required_membership: str
220    """The required correct membership for errored user."""
221
222    def into_membership(
223        self, value: typing.Optional[str] = None
224    ) -> enums.MembershipType:
225        """Turn the required membership from `str` into `aiobungie.Membership` type.
226
227        If value parameter is not provided it will fall back to the required membership.
228        """
229        if value is None:
230            return _DETERMINE_MSHIP(self.required_membership)
231        return _DETERMINE_MSHIP(value)
232
233    def __str__(self) -> str:
234        return (
235            f"Expected membership: {self.into_membership().name.replace('_', '').title()}, "
236            f"But got {self.into_membership(self.membership_type)} for id {self.membership_id}"
237        )
238
239    def __int__(self) -> int:
240        return int(self.membership_id)

A bad request error raised when passing wrong membership to the request.

Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.

Example
try:
    profile = await client.fetch_profile(
        member_id=1,
        type=aiobungie.MembershipType.STADIA,
        components=[]
    )

# Membership type is wrong!
except aiobungie.MembershipTypeError as err:
    correct_membersip = err.into_membership()
    profile_id = err.membership_id

    # Recall the method.
    profile = await client.fetch_profile(
        member_id=profile_id,
        type=correct_membership,
        components=[]
    )
MembershipTypeError( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], membership_type: str, membership_id: int, required_membership: str)
 2def __init__(self, message, url, body, headers, membership_type, membership_id, required_membership):
 3    self.message = message
 4    self.url = url
 5    self.body = body
 6    self.headers = headers
 7    self.http_status = attr_dict['http_status'].default
 8    self.membership_type = membership_type
 9    self.membership_id = membership_id
10    self.required_membership = required_membership
11    BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.membership_type,self.membership_id,self.required_membership)

Method generated by attrs for class MembershipTypeError.

membership_type: str

The errored membership type passed to the request.

membership_id: int

The errored user's membership id.

required_membership: str

The required correct membership for errored user.

def into_membership( self, value: Optional[str] = None) -> MembershipType:
222    def into_membership(
223        self, value: typing.Optional[str] = None
224    ) -> enums.MembershipType:
225        """Turn the required membership from `str` into `aiobungie.Membership` type.
226
227        If value parameter is not provided it will fall back to the required membership.
228        """
229        if value is None:
230            return _DETERMINE_MSHIP(self.required_membership)
231        return _DETERMINE_MSHIP(value)

Turn the required membership from str into aiobungie.Membership type.

If value parameter is not provided it will fall back to the required membership.

Inherited Members
BadRequest
url
body
headers
http_status
HTTPError
message
builtins.BaseException
with_traceback
args
@typing.final
class MilestoneType(builtins.int, aiobungie.Enum):
505@typing.final
506class MilestoneType(int, Enum):
507    """An Enum for Destiny 2 milestone types."""
508
509    UNKNOWN = 0
510    TUTORIAL = 1
511    ONETIME = 2
512    WEEKLY = 3
513    DAILY = 4
514    SPECIAL = 5

An Enum for Destiny 2 milestone types.

UNKNOWN = <MilestoneType.UNKNOWN: 0>
TUTORIAL = <MilestoneType.TUTORIAL: 1>
ONETIME = <MilestoneType.ONETIME: 2>
WEEKLY = <MilestoneType.WEEKLY: 3>
DAILY = <MilestoneType.DAILY: 4>
SPECIAL = <MilestoneType.SPECIAL: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class NotFound(aiobungie.HTTPException):
146@attrs.define(auto_exc=True)
147class NotFound(HTTPException):
148    """Raised when an unknown resource was not found."""
149
150    http_status: http.HTTPStatus = attrs.field(
151        default=http.HTTPStatus.NOT_FOUND, init=False
152    )

Raised when an unknown resource was not found.

NotFound( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class NotFound.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class ObjectiveUIStyle(builtins.int, aiobungie.Enum):
 94@typing.final
 95class ObjectiveUIStyle(int, enums.Enum):
 96    NONE = 0
 97    HIGHLIGHTED = 1
 98    CRAFTING_WEAPON_LEVEL = 2
 99    CRAFTING_WEAPON_LEVEL_PROGRESS = 3
100    CRAFTING_WEAPON_TIMESTAMP = 4
101    CRAFTING_MEMENTOS = 5
102    CRAFTING_MEMENTO_TITLE = 6

An enumeration.

NONE = <ObjectiveUIStyle.NONE: 0>
HIGHLIGHTED = <ObjectiveUIStyle.HIGHLIGHTED: 1>
CRAFTING_WEAPON_LEVEL = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL: 2>
CRAFTING_WEAPON_LEVEL_PROGRESS = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL_PROGRESS: 3>
CRAFTING_WEAPON_TIMESTAMP = <ObjectiveUIStyle.CRAFTING_WEAPON_TIMESTAMP: 4>
CRAFTING_MEMENTOS = <ObjectiveUIStyle.CRAFTING_MEMENTOS: 5>
CRAFTING_MEMENTO_TITLE = <ObjectiveUIStyle.CRAFTING_MEMENTO_TITLE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Place(builtins.int, aiobungie.Enum):
230@typing.final
231class Place(int, Enum):
232    """An Enum for Destiny 2 Places and NOT Planets"""
233
234    ORBIT = 2961497387
235    SOCIAL = 4151112093
236    LIGHT_HOUSE = 4276116472
237    EXPLORE = 3497767639

An Enum for Destiny 2 Places and NOT Planets

ORBIT = <Place.ORBIT: 2961497387>
SOCIAL = <Place.SOCIAL: 4151112093>
LIGHT_HOUSE = <Place.LIGHT_HOUSE: 4276116472>
EXPLORE = <Place.EXPLORE: 3497767639>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Planet(builtins.int, aiobungie.Enum):
195@typing.final
196class Planet(int, Enum):
197    """An Enum for all available planets in Destiny 2."""
198
199    UNKNOWN = 0
200    """Unknown space"""
201
202    EARTH = 3747705955
203    """Earth"""
204
205    DREAMING_CITY = 2877881518
206    """The Dreaming city."""
207
208    NESSUS = 3526908984
209    """Nessus"""
210
211    MOON = 3325508439
212    """The Moon"""
213
214    COSMODROME = 3990611421
215    """The Cosmodrome"""
216
217    TANGLED_SHORE = 3821439926
218    """The Tangled Shore"""
219
220    VENUS = 3871070152
221    """Venus"""
222
223    EAZ = 541863059  # Exclusive event.
224    """European Aerial Zone"""
225
226    EUROPA = 1729879943
227    """Europa"""

An Enum for all available planets in Destiny 2.

UNKNOWN = <Planet.UNKNOWN: 0>

Unknown space

EARTH = <Planet.EARTH: 3747705955>

Earth

DREAMING_CITY = <Planet.DREAMING_CITY: 2877881518>

The Dreaming city.

NESSUS = <Planet.NESSUS: 3526908984>

Nessus

MOON = <Planet.MOON: 3325508439>

The Moon

COSMODROME = <Planet.COSMODROME: 3990611421>

The Cosmodrome

TANGLED_SHORE = <Planet.TANGLED_SHORE: 3821439926>

The Tangled Shore

VENUS = <Planet.VENUS: 3871070152>

Venus

EAZ = <Planet.EAZ: 541863059>

European Aerial Zone

EUROPA = <Planet.EUROPA: 1729879943>

Europa

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Presence(builtins.int, aiobungie.Enum):
682@typing.final
683class Presence(int, Enum):
684    """An enum for a bungie friend status."""
685
686    OFFLINE_OR_UNKNOWN = 0
687    ONLINE = 1

An enum for a bungie friend status.

OFFLINE_OR_UNKNOWN = <Presence.OFFLINE_OR_UNKNOWN: 0>
ONLINE = <Presence.ONLINE: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class PrivacySetting(builtins.int, aiobungie.Enum):
770@typing.final
771class PrivacySetting(int, Enum):
772    """An enum for players's privacy settings."""
773
774    OPEN = 0
775    CLAN_AND_FRIENDS = 1
776    FRIENDS_ONLY = 2
777    INVITE_ONLY = 3
778    CLOSED = 4

An enum for players's privacy settings.

OPEN = <PrivacySetting.OPEN: 0>
CLAN_AND_FRIENDS = <PrivacySetting.CLAN_AND_FRIENDS: 1>
FRIENDS_ONLY = <PrivacySetting.FRIENDS_ONLY: 2>
INVITE_ONLY = <PrivacySetting.INVITE_ONLY: 3>
CLOSED = <PrivacySetting.CLOSED: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class RESTClient(aiobungie.interfaces.rest.RESTInterface):
 313class RESTClient(interfaces.RESTInterface):
 314    """A RESTful client implementation for Bungie's API.
 315
 316    This client is designed to only make HTTP requests and return JSON objects
 317    to provide RESTful functionality.
 318
 319    This client is also used within `aiobungie.Client` which deserialize those returned JSON objects
 320    using the factory into Pythonic data classes objects which provide Python functionality.
 321
 322    Example
 323    -------
 324    ```py
 325    import aiobungie
 326
 327    async def main():
 328        async with aiobungie.RESTClient("TOKEN") as rest_client:
 329            req = await rest_client.fetch_clan_members(4389205)
 330            clan_members = req['results']
 331            for member in clan_members:
 332                for k, v in member['destinyUserInfo'].items():
 333                    print(k, v)
 334    ```
 335
 336    Parameters
 337    ----------
 338    token : `str`
 339        A valid application token from Bungie's developer portal.
 340
 341    Other Parameters
 342    ----------------
 343    max_retries : `int`
 344        The max retries number to retry if the request hit a `5xx` status code.
 345    client_secret : `typing.Optional[str]`
 346        An optional application client secret,
 347        This is only needed if you're fetching OAuth2 tokens with this client.
 348    client_id : `typing.Optional[int]`
 349        An optional application client id,
 350        This is only needed if you're fetching OAuth2 tokens with this client.
 351    enable_debugging : `bool | str`
 352        Whether to enable logging responses or not.
 353
 354    Logging Levels
 355    --------------
 356    * `False`: This will disable logging.
 357    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
 358    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
 359    """
 360
 361    __slots__ = (
 362        "_token",
 363        "_session",
 364        "_lock",
 365        "_max_retries",
 366        "_client_secret",
 367        "_client_id",
 368        "_metadata",
 369    )
 370
 371    def __init__(
 372        self,
 373        token: str,
 374        /,
 375        *,
 376        client_secret: typing.Optional[str] = None,
 377        client_id: typing.Optional[int] = None,
 378        client_session: typing.Optional[aiohttp.ClientSession] = None,
 379        max_retries: int = 4,
 380        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 381    ) -> None:
 382        self._session: typing.Optional[aiohttp.ClientSession] = client_session
 383        self._lock: typing.Optional[asyncio.Lock] = None
 384        self._client_secret = client_secret
 385        self._client_id = client_id
 386        self._token: str = token
 387        self._max_retries = max_retries
 388        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
 389
 390        self._set_debug_level(enable_debugging)
 391
 392    @property
 393    def client_id(self) -> typing.Optional[int]:
 394        return self._client_id
 395
 396    @property
 397    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 398        return self._metadata
 399
 400    @property
 401    def is_alive(self) -> bool:
 402        return self._session is not None
 403
 404    @typing.final
 405    async def close(self) -> None:
 406        if self._session is None:
 407            raise RuntimeError("REST client is not running.")
 408
 409        await self._session.close()
 410        self._session = None
 411
 412    @typing.final
 413    def open(self) -> None:
 414        """Open a new client session. This is called internally with contextmanager usage."""
 415        if self._session:
 416            raise RuntimeError("Cannot open REST client when it's already open.")
 417
 418        self._session = aiohttp.ClientSession(
 419            connector=aiohttp.TCPConnector(ssl=False),
 420            raise_for_status=False,
 421            timeout=aiohttp.ClientTimeout(total=30.0),
 422        )
 423
 424    @typing.final
 425    def enable_debugging(
 426        self,
 427        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 428        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
 429        /,
 430    ) -> None:
 431        self._set_debug_level(level, file)
 432
 433    @typing.final
 434    async def static_request(
 435        self,
 436        method: typing.Union[RequestMethod, str],
 437        path: str,
 438        *,
 439        auth: typing.Optional[str] = None,
 440        json: typing.Optional[dict[str, typing.Any]] = None,
 441    ) -> ResponseSig:
 442        return await self._request(method, path, auth=auth, json=json)
 443
 444    @typing.final
 445    def build_oauth2_url(
 446        self, client_id: typing.Optional[int] = None
 447    ) -> typing.Optional[builders.OAuthURL]:
 448        client_id = client_id or self._client_id
 449        if client_id is None:
 450            return None
 451
 452        return builders.OAuthURL(client_id=client_id)
 453
 454    @staticmethod
 455    def _set_debug_level(
 456        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 457        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
 458    ) -> None:
 459        file_handler = logging.FileHandler(file, mode="w") if file else None
 460        if level == "TRACE" or level == TRACE:
 461            logging.basicConfig(
 462                level=TRACE, handlers=[file_handler] if file_handler else None
 463            )
 464
 465        elif level:
 466            logging.basicConfig(
 467                level=logging.DEBUG, handlers=[file_handler] if file_handler else None
 468            )
 469
 470    async def _request(
 471        self,
 472        method: typing.Union[RequestMethod, str],
 473        route: str,
 474        *,
 475        base: bool = False,
 476        oauth2: bool = False,
 477        auth: typing.Optional[str] = None,
 478        unwrapping: typing.Literal["json", "read"] = "json",
 479        json: typing.Optional[dict[str, typing.Any]] = None,
 480        headers: typing.Optional[dict[str, typing.Any]] = None,
 481        data: typing.Optional[typing.Union[str, dict[str, typing.Any]]] = None,
 482    ) -> ResponseSig:
 483        # This is not None when opening the client.
 484        assert self._session is not None
 485
 486        retries: int = 0
 487        headers = headers or {}
 488
 489        headers.setdefault(_USER_AGENT_HEADERS, _USER_AGENT)
 490        headers["X-API-KEY"] = self._token
 491
 492        if auth is not None:
 493            headers[_AUTH_HEADER] = f"Bearer {auth}"
 494
 495        # Handling endpoints
 496        endpoint = url.BASE
 497
 498        if not base:
 499            endpoint = endpoint + url.REST_EP
 500
 501        if oauth2:
 502            headers["Content-Type"] = "application/x-www-form-urlencoded"
 503            endpoint = endpoint + url.TOKEN_EP
 504
 505        if self._lock is None:
 506            self._lock = asyncio.Lock()
 507
 508        while True:
 509            async with (stack := contextlib.AsyncExitStack()):
 510                await stack.enter_async_context(self._lock)
 511
 512                # We make the request here.
 513                taken_time = time.monotonic()
 514                response = await stack.enter_async_context(
 515                    self._session.request(
 516                        method=method,
 517                        url=f"{endpoint}/{route}",
 518                        json=json,
 519                        headers=headers,
 520                        data=data,
 521                    )
 522                )
 523                response_time = (time.monotonic() - taken_time) * 1_000
 524
 525                _LOG.debug(
 526                    "%s %s %s Time %.4fms",
 527                    method,
 528                    f"{endpoint}/{route}",
 529                    f"{response.status} {response.reason}",
 530                    response_time,
 531                )
 532
 533                await self._handle_ratelimit(response, method, route)
 534
 535                if response.status == http.HTTPStatus.NO_CONTENT:
 536                    return None
 537
 538                if 300 > response.status >= 200:
 539                    if unwrapping == "read":
 540                        # We need to read the bytes for the manifest response.
 541                        return await response.read()
 542
 543                    if response.content_type == _APP_JSON:
 544                        json_data = await response.json()
 545
 546                        _LOG.debug(
 547                            "%s %s %s Time %.4fms",
 548                            method,
 549                            f"{endpoint}/{route}",
 550                            f"{response.status} {response.reason}",
 551                            response_time,
 552                        )
 553
 554                        if _LOG.isEnabledFor(TRACE):
 555                            cloned = headers.copy()
 556                            cloned.update(response.headers)  # type: ignore
 557
 558                            _LOG.log(
 559                                TRACE,
 560                                "%s",
 561                                error.stringify_http_message(cloned),
 562                            )
 563
 564                        # Return the response.
 565                        # oauth2 responses are not packed inside a Response object.
 566                        if oauth2:
 567                            return json_data  # type: ignore[no-any-return]
 568
 569                        return json_data["Response"]  # type: ignore[no-any-return]
 570
 571                if (
 572                    response.status in _RETRY_5XX
 573                    and retries < self._max_retries  # noqa: W503
 574                ):
 575                    backoff_ = backoff.ExponentialBackOff(maximum=6)
 576                    sleep_time = next(backoff_)
 577                    _LOG.warning(
 578                        "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i",
 579                        response.status,
 580                        response.reason,
 581                        sleep_time,
 582                        self._max_retries - retries,
 583                    )
 584
 585                    retries += 1
 586                    await asyncio.sleep(sleep_time)
 587                    continue
 588
 589                raise await error.raise_error(response)
 590
 591    if not typing.TYPE_CHECKING:
 592
 593        def __enter__(self) -> typing.NoReturn:
 594            cls = type(self)
 595            raise TypeError(
 596                f"{cls.__qualname__} is async only, use 'async with' instead."
 597            )
 598
 599        def __exit__(
 600            self,
 601            exception_type: typing.Optional[type[BaseException]],
 602            exception: typing.Optional[BaseException],
 603            exception_traceback: typing.Optional[types.TracebackType],
 604        ) -> None:
 605            ...
 606
 607    async def __aenter__(self) -> RESTClient:
 608        self.open()
 609        return self
 610
 611    async def __aexit__(
 612        self,
 613        exception_type: typing.Optional[type[BaseException]],
 614        exception: typing.Optional[BaseException],
 615        exception_traceback: typing.Optional[types.TracebackType],
 616    ) -> None:
 617        await self.close()
 618
 619    # We don't want this to be super complicated.
 620    @typing.final
 621    async def _handle_ratelimit(
 622        self,
 623        response: aiohttp.ClientResponse,
 624        method: str,
 625        route: str,
 626    ) -> None:
 627        if response.status != http.HTTPStatus.TOO_MANY_REQUESTS:
 628            return
 629
 630        if response.content_type != _APP_JSON:
 631            raise error.HTTPError(
 632                f"Being ratelimited on non JSON request, {response.content_type}.",
 633                http.HTTPStatus.TOO_MANY_REQUESTS,
 634            )
 635
 636        json: typedefs.JSONObject = await response.json()
 637        retry_after = float(json.get("ThrottleSeconds", 15.0)) + 0.1
 638        max_calls: int = 0
 639
 640        while True:
 641            if max_calls == 10:
 642                # Max retries by default. We raise an error here.
 643                raise error.RateLimitedError(
 644                    body=json,
 645                    url=str(response.real_url),
 646                    retry_after=retry_after,
 647                )
 648
 649            # We sleep for a little bit to avoid funky behavior.
 650            _LOG.warning(
 651                "We're being ratelimited, Method %s Route %s. Sleeping for %.2fs.",
 652                method,
 653                route,
 654                retry_after,
 655            )
 656            await asyncio.sleep(retry_after)
 657            max_calls += 1
 658            continue
 659
 660    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
 661        if not isinstance(self._client_secret, (str, int)):
 662            raise TypeError(
 663                "Expected (str, int) for client secret "
 664                f"but got {type(self._client_secret).__name__}"  # type: ignore
 665            )
 666
 667        headers = {
 668            "client_secret": self._client_secret,
 669        }
 670
 671        data = (
 672            f"grant_type=authorization_code&code={code}"
 673            f"&client_id={self._client_id}&client_secret={self._client_secret}"
 674        )
 675
 676        response = await self._request(
 677            RequestMethod.POST, "", headers=headers, data=data, oauth2=True
 678        )
 679        assert isinstance(response, dict)
 680        return builders.OAuth2Response.build_response(response)
 681
 682    async def refresh_access_token(
 683        self, refresh_token: str, /
 684    ) -> builders.OAuth2Response:
 685        if not isinstance(self._client_secret, (int, str)):
 686            raise TypeError(
 687                f"Expected (str, int) for client secret but got {type(self._client_secret).__name__}"  # type: ignore
 688            )
 689
 690        data = {
 691            "grant_type": "refresh_token",
 692            "refresh_token": refresh_token,
 693            "client_id": self._client_id,
 694            "client_secret": self._client_secret,
 695            "Content-Type": "application/x-www-form-urlencoded",
 696        }
 697
 698        response = await self._request(RequestMethod.POST, "", data=data, oauth2=True)
 699        assert isinstance(response, dict)
 700        return builders.OAuth2Response.build_response(response)
 701
 702    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
 703        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 704        resp = await self._request(
 705            RequestMethod.GET, f"User/GetBungieNetUserById/{id}/"
 706        )
 707        assert isinstance(resp, dict)
 708        return resp
 709
 710    async def fetch_user_themes(self) -> typedefs.JSONArray:
 711        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 712        resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/")
 713        assert isinstance(resp, list)
 714        return resp
 715
 716    async def fetch_membership_from_id(
 717        self,
 718        id: int,
 719        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 720        /,
 721    ) -> typedefs.JSONObject:
 722        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 723        resp = await self._request(
 724            RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}"
 725        )
 726        assert isinstance(resp, dict)
 727        return resp
 728
 729    async def fetch_player(
 730        self,
 731        name: str,
 732        code: int,
 733        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
 734        /,
 735    ) -> typedefs.JSONArray:
 736        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 737        resp = await self._request(
 738            RequestMethod.POST,
 739            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
 740            json={"displayName": name, "displayNameCode": code},
 741        )
 742        assert isinstance(resp, list)
 743        return resp
 744
 745    async def search_users(self, name: str, /) -> typedefs.JSONObject:
 746        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 747        resp = await self._request(
 748            RequestMethod.POST,
 749            "User/Search/GlobalName/0",
 750            json={"displayNamePrefix": name},
 751        )
 752        assert isinstance(resp, dict)
 753        return resp
 754
 755    async def fetch_clan_from_id(
 756        self, id: int, /, access_token: typing.Optional[str] = None
 757    ) -> typedefs.JSONObject:
 758        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 759        resp = await self._request(
 760            RequestMethod.GET, f"GroupV2/{id}", auth=access_token
 761        )
 762        assert isinstance(resp, dict)
 763        return resp
 764
 765    async def fetch_clan(
 766        self,
 767        name: str,
 768        /,
 769        access_token: typing.Optional[str] = None,
 770        *,
 771        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 772    ) -> typedefs.JSONObject:
 773        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 774        resp = await self._request(
 775            RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
 776        )
 777        assert isinstance(resp, dict)
 778        return resp
 779
 780    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
 781        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 782        resp = await self._request(
 783            RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/"
 784        )
 785        assert isinstance(resp, dict)
 786        return resp
 787
 788    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
 789        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 790        resp = await self._request(
 791            RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/"
 792        )
 793        assert isinstance(resp, list)
 794        return resp
 795
 796    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
 797        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 798        resp = await self._request(RequestMethod.GET, f"App/Application/{appid}")
 799        assert isinstance(resp, dict)
 800        return resp
 801
 802    async def fetch_character(
 803        self,
 804        member_id: int,
 805        membership_type: typedefs.IntAnd[enums.MembershipType],
 806        character_id: int,
 807        components: list[enums.ComponentType],
 808        auth: typing.Optional[str] = None,
 809    ) -> typedefs.JSONObject:
 810        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 811        collector = _collect_components(components)
 812        response = await self._request(
 813            RequestMethod.GET,
 814            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
 815            f"Character/{character_id}/?components={collector}",
 816            auth=auth,
 817        )
 818        assert isinstance(response, dict)
 819        return response
 820
 821    async def fetch_activities(
 822        self,
 823        member_id: int,
 824        character_id: int,
 825        mode: typedefs.IntAnd[enums.GameMode],
 826        membership_type: typedefs.IntAnd[
 827            enums.MembershipType
 828        ] = enums.MembershipType.ALL,
 829        *,
 830        page: int = 0,
 831        limit: int = 1,
 832    ) -> typedefs.JSONObject:
 833        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 834        resp = await self._request(
 835            RequestMethod.GET,
 836            f"Destiny2/{int(membership_type)}/Account/"
 837            f"{member_id}/Character/{character_id}/Stats/Activities"
 838            f"/?mode={int(mode)}&count={limit}&page={page}",
 839        )
 840        assert isinstance(resp, dict)
 841        return resp
 842
 843    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
 844        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 845        resp = await self._request(
 846            RequestMethod.GET,
 847            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
 848        )
 849        assert isinstance(resp, dict)
 850        return resp
 851
 852    async def fetch_profile(
 853        self,
 854        membership_id: int,
 855        type: typedefs.IntAnd[enums.MembershipType],
 856        components: list[enums.ComponentType],
 857        auth: typing.Optional[str] = None,
 858    ) -> typedefs.JSONObject:
 859        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 860        collector = _collect_components(components)
 861        response = await self._request(
 862            RequestMethod.GET,
 863            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
 864            auth=auth,
 865        )
 866        assert isinstance(response, dict)
 867        return response
 868
 869    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
 870        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 871        response = await self._request(
 872            RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}"
 873        )
 874        assert isinstance(response, dict)
 875        return response
 876
 877    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
 878        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 879        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
 880        assert isinstance(resp, dict)
 881        return resp
 882
 883    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
 884        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 885        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
 886        assert isinstance(resp, dict)
 887        return resp
 888
 889    async def fetch_groups_for_member(
 890        self,
 891        member_id: int,
 892        member_type: typedefs.IntAnd[enums.MembershipType],
 893        /,
 894        *,
 895        filter: int = 0,
 896        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 897    ) -> typedefs.JSONObject:
 898        resp = await self._request(
 899            RequestMethod.GET,
 900            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 901        )
 902        assert isinstance(resp, dict)
 903        return resp
 904
 905    async def fetch_potential_groups_for_member(
 906        self,
 907        member_id: int,
 908        member_type: typedefs.IntAnd[enums.MembershipType],
 909        /,
 910        *,
 911        filter: int = 0,
 912        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 913    ) -> typedefs.JSONObject:
 914        resp = await self._request(
 915            RequestMethod.GET,
 916            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 917        )
 918        assert isinstance(resp, dict)
 919        return resp
 920
 921    async def fetch_clan_members(
 922        self,
 923        clan_id: int,
 924        /,
 925        *,
 926        name: typing.Optional[str] = None,
 927        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 928    ) -> typedefs.JSONObject:
 929        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 930        resp = await self._request(
 931            RequestMethod.GET,
 932            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
 933        )
 934        assert isinstance(resp, dict)
 935        return resp
 936
 937    async def fetch_hardlinked_credentials(
 938        self,
 939        credential: int,
 940        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
 941        /,
 942    ) -> typedefs.JSONObject:
 943        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 944        resp = await self._request(
 945            RequestMethod.GET,
 946            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
 947        )
 948        assert isinstance(resp, dict)
 949        return resp
 950
 951    async def fetch_user_credentials(
 952        self, access_token: str, membership_id: int, /
 953    ) -> typedefs.JSONArray:
 954        resp = await self._request(
 955            RequestMethod.GET,
 956            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
 957            auth=access_token,
 958        )
 959        assert isinstance(resp, list)
 960        return resp
 961
 962    async def insert_socket_plug(
 963        self,
 964        action_token: str,
 965        /,
 966        instance_id: int,
 967        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
 968        character_id: int,
 969        membership_type: typedefs.IntAnd[enums.MembershipType],
 970    ) -> typedefs.JSONObject:
 971        if isinstance(plug, builders.PlugSocketBuilder):
 972            plug = plug.collect()
 973
 974        body = {
 975            "actionToken": action_token,
 976            "itemInstanceId": instance_id,
 977            "plug": plug,
 978            "characterId": character_id,
 979            "membershipType": int(membership_type),
 980        }
 981        resp = await self._request(
 982            RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
 983        )
 984        assert isinstance(resp, dict)
 985        return resp
 986
 987    async def insert_socket_plug_free(
 988        self,
 989        access_token: str,
 990        /,
 991        instance_id: int,
 992        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
 993        character_id: int,
 994        membership_type: typedefs.IntAnd[enums.MembershipType],
 995    ) -> typedefs.JSONObject:
 996        if isinstance(plug, builders.PlugSocketBuilder):
 997            plug = plug.collect()
 998
 999        body = {
1000            "itemInstanceId": instance_id,
1001            "plug": plug,
1002            "characterId": character_id,
1003            "membershipType": int(membership_type),
1004        }
1005        resp = await self._request(
1006            RequestMethod.POST,
1007            "Destiny2/Actions/Items/InsertSocketPlugFree",
1008            json=body,
1009            auth=access_token,
1010        )
1011        assert isinstance(resp, dict)
1012        return resp
1013
1014    async def set_item_lock_state(
1015        self,
1016        access_token: str,
1017        state: bool,
1018        /,
1019        item_id: int,
1020        character_id: int,
1021        membership_type: typedefs.IntAnd[enums.MembershipType],
1022    ) -> int:
1023        body = {
1024            "state": state,
1025            "itemId": item_id,
1026            "characterId": character_id,
1027            "membershipType": int(membership_type),
1028        }
1029        response = await self._request(
1030            RequestMethod.POST,
1031            "Destiny2/Actions/Items/SetLockState",
1032            json=body,
1033            auth=access_token,
1034        )
1035        assert isinstance(response, int)
1036        return response
1037
1038    async def set_quest_track_state(
1039        self,
1040        access_token: str,
1041        state: bool,
1042        /,
1043        item_id: int,
1044        character_id: int,
1045        membership_type: typedefs.IntAnd[enums.MembershipType],
1046    ) -> int:
1047        body = {
1048            "state": state,
1049            "itemId": item_id,
1050            "characterId": character_id,
1051            "membership_type": int(membership_type),
1052        }
1053        response = await self._request(
1054            RequestMethod.POST,
1055            "Destiny2/Actions/Items/SetTrackedState",
1056            json=body,
1057            auth=access_token,
1058        )
1059        assert isinstance(response, int)
1060        return response
1061
1062    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1063        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1064        path = await self._request(RequestMethod.GET, "Destiny2/Manifest")
1065        assert isinstance(path, dict)
1066        return path
1067
1068    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1069        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1070        _ensure_manifest_language(language)
1071
1072        content = await self.fetch_manifest_path()
1073        resp = await self._request(
1074            RequestMethod.GET,
1075            content["mobileWorldContentPaths"][language],
1076            unwrapping="read",
1077            base=True,
1078        )
1079        assert isinstance(resp, bytes)
1080        return resp
1081
1082    async def download_manifest(
1083        self,
1084        language: str = "en",
1085        name: str = "manifest",
1086        path: typing.Union[pathlib.Path, str] = ".",
1087        *,
1088        force: bool = False,
1089    ) -> None:
1090        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1091        complete_path = _get_path(name, path, sql=True)
1092
1093        if complete_path.exists() and force:
1094            if force:
1095                _LOG.info(
1096                    f"Found manifest in {complete_path!s}. Forcing to Re-Download."
1097                )
1098                complete_path.unlink(missing_ok=True)
1099
1100                return await self.download_manifest(language, name, path, force=force)
1101
1102            else:
1103                raise FileExistsError(
1104                    "Manifest file already exists, "
1105                    "To force download, set the `force` parameter to `True`."
1106                )
1107
1108        _LOG.info(f"Downloading manifest. Location: {complete_path!s}")
1109        data_bytes = await self.read_manifest_bytes(language)
1110        await asyncio.get_running_loop().run_in_executor(
1111            None, _write_sqlite_bytes, data_bytes, path, name
1112        )
1113
1114    async def download_json_manifest(
1115        self,
1116        file_name: str = "manifest",
1117        path: typing.Union[str, pathlib.Path] = ".",
1118        language: str = "en",
1119    ) -> None:
1120        _ensure_manifest_language(language)
1121
1122        _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...")
1123
1124        content = await self.fetch_manifest_path()
1125        json_bytes = await self._request(
1126            RequestMethod.GET,
1127            content["jsonWorldContentPaths"][language],
1128            unwrapping="read",
1129            base=True,
1130        )
1131
1132        await asyncio.get_running_loop().run_in_executor(
1133            None, _write_json_bytes, json_bytes, file_name, path
1134        )
1135        _LOG.info("Finished downloading manifest JSON.")
1136
1137    async def fetch_manifest_version(self) -> str:
1138        return typing.cast(str, (await self.fetch_manifest_path())["version"])
1139
1140    async def fetch_linked_profiles(
1141        self,
1142        member_id: int,
1143        member_type: typedefs.IntAnd[enums.MembershipType],
1144        /,
1145        *,
1146        all: bool = False,
1147    ) -> typedefs.JSONObject:
1148        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1149        resp = await self._request(
1150            RequestMethod.GET,
1151            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1152        )
1153        assert isinstance(resp, dict)
1154        return resp
1155
1156    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1157        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1158        resp = await self._request(
1159            RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/"
1160        )
1161        assert isinstance(resp, dict)
1162        return resp
1163
1164    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1165        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1166        resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/")
1167        assert isinstance(resp, dict)
1168        return resp
1169
1170    async def fetch_public_milestone_content(
1171        self, milestone_hash: int, /
1172    ) -> typedefs.JSONObject:
1173        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1174        resp = await self._request(
1175            RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1176        )
1177        assert isinstance(resp, dict)
1178        return resp
1179
1180    async def fetch_current_user_memberships(
1181        self, access_token: str, /
1182    ) -> typedefs.JSONObject:
1183        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1184        resp = await self._request(
1185            RequestMethod.GET,
1186            "User/GetMembershipsForCurrentUser/",
1187            auth=access_token,
1188        )
1189        assert isinstance(resp, dict)
1190        return resp
1191
1192    async def equip_item(
1193        self,
1194        access_token: str,
1195        /,
1196        item_id: int,
1197        character_id: int,
1198        membership_type: typedefs.IntAnd[enums.MembershipType],
1199    ) -> None:
1200        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1201        payload = {
1202            "itemId": item_id,
1203            "characterId": character_id,
1204            "membershipType": int(membership_type),
1205        }
1206
1207        await self._request(
1208            RequestMethod.POST,
1209            "Destiny2/Actions/Items/EquipItem/",
1210            json=payload,
1211            auth=access_token,
1212        )
1213
1214    async def equip_items(
1215        self,
1216        access_token: str,
1217        /,
1218        item_ids: list[int],
1219        character_id: int,
1220        membership_type: typedefs.IntAnd[enums.MembershipType],
1221    ) -> None:
1222        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1223        payload = {
1224            "itemIds": item_ids,
1225            "characterId": character_id,
1226            "membershipType": int(membership_type),
1227        }
1228        await self._request(
1229            RequestMethod.POST,
1230            "Destiny2/Actions/Items/EquipItems/",
1231            json=payload,
1232            auth=access_token,
1233        )
1234
1235    async def ban_clan_member(
1236        self,
1237        access_token: str,
1238        /,
1239        group_id: int,
1240        membership_id: int,
1241        membership_type: typedefs.IntAnd[enums.MembershipType],
1242        *,
1243        length: int = 0,
1244        comment: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1245    ) -> None:
1246        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1247        payload = {"comment": str(comment), "length": length}
1248        await self._request(
1249            RequestMethod.POST,
1250            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1251            json=payload,
1252            auth=access_token,
1253        )
1254
1255    async def unban_clan_member(
1256        self,
1257        access_token: str,
1258        /,
1259        group_id: int,
1260        membership_id: int,
1261        membership_type: typedefs.IntAnd[enums.MembershipType],
1262    ) -> None:
1263        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1264        await self._request(
1265            RequestMethod.POST,
1266            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1267            auth=access_token,
1268        )
1269
1270    async def kick_clan_member(
1271        self,
1272        access_token: str,
1273        /,
1274        group_id: int,
1275        membership_id: int,
1276        membership_type: typedefs.IntAnd[enums.MembershipType],
1277    ) -> typedefs.JSONObject:
1278        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1279        resp = await self._request(
1280            RequestMethod.POST,
1281            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1282            auth=access_token,
1283        )
1284        assert isinstance(resp, dict)
1285        return resp
1286
1287    async def edit_clan(
1288        self,
1289        access_token: str,
1290        /,
1291        group_id: int,
1292        *,
1293        name: typedefs.NoneOr[str] = None,
1294        about: typedefs.NoneOr[str] = None,
1295        motto: typedefs.NoneOr[str] = None,
1296        theme: typedefs.NoneOr[str] = None,
1297        tags: typedefs.NoneOr[collections.Sequence[str]] = None,
1298        is_public: typedefs.NoneOr[bool] = None,
1299        locale: typedefs.NoneOr[str] = None,
1300        avatar_image_index: typedefs.NoneOr[int] = None,
1301        membership_option: typedefs.NoneOr[
1302            typedefs.IntAnd[enums.MembershipOption]
1303        ] = None,
1304        allow_chat: typedefs.NoneOr[bool] = None,
1305        chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None,
1306        call_sign: typedefs.NoneOr[str] = None,
1307        homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1308        enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None,
1309        default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1310        is_public_topic_admin: typedefs.NoneOr[bool] = None,
1311    ) -> None:
1312        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1313        payload = {
1314            "name": name,
1315            "about": about,
1316            "motto": motto,
1317            "theme": theme,
1318            "tags": tags,
1319            "isPublic": is_public,
1320            "avatarImageIndex": avatar_image_index,
1321            "isPublicTopicAdminOnly": is_public_topic_admin,
1322            "allowChat": allow_chat,
1323            "chatSecurity": chat_security,
1324            "callsign": call_sign,
1325            "homepage": homepage,
1326            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1327            "defaultPublicity": default_publicity,
1328            "locale": locale,
1329        }
1330        if membership_option is not None:
1331            payload["membershipOption"] = int(membership_option)
1332
1333        await self._request(
1334            RequestMethod.POST,
1335            f"GroupV2/{group_id}/Edit",
1336            json=payload,
1337            auth=access_token,
1338        )
1339
1340    async def edit_clan_options(
1341        self,
1342        access_token: str,
1343        /,
1344        group_id: int,
1345        *,
1346        invite_permissions_override: typedefs.NoneOr[bool] = None,
1347        update_culture_permissionOverride: typedefs.NoneOr[bool] = None,
1348        host_guided_game_permission_override: typedefs.NoneOr[
1349            typing.Literal[0, 1, 2]
1350        ] = None,
1351        update_banner_permission_override: typedefs.NoneOr[bool] = None,
1352        join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None,
1353    ) -> None:
1354        payload = {
1355            "InvitePermissionOverride": invite_permissions_override,
1356            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1357            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1358            "UpdateBannerPermissionOverride": update_banner_permission_override,
1359            "JoinLevel": int(join_level) if join_level else None,
1360        }
1361
1362        await self._request(
1363            RequestMethod.POST,
1364            f"GroupV2/{group_id}/EditFounderOptions",
1365            json=payload,
1366            auth=access_token,
1367        )
1368
1369    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1370        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1371        resp = await self._request(
1372            RequestMethod.GET,
1373            "Social/Friends/",
1374            auth=access_token,
1375        )
1376        assert isinstance(resp, dict)
1377        return resp
1378
1379    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1380        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1381        resp = await self._request(
1382            RequestMethod.GET,
1383            "Social/Friends/Requests",
1384            auth=access_token,
1385        )
1386        assert isinstance(resp, dict)
1387        return resp
1388
1389    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1390        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1391        await self._request(
1392            RequestMethod.POST,
1393            f"Social/Friends/Requests/Accept/{member_id}",
1394            auth=access_token,
1395        )
1396
1397    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1398        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1399        await self._request(
1400            RequestMethod.POST,
1401            f"Social/Friends/Add/{member_id}",
1402            auth=access_token,
1403        )
1404
1405    async def decline_friend_request(
1406        self, access_token: str, /, member_id: int
1407    ) -> None:
1408        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1409        await self._request(
1410            RequestMethod.POST,
1411            f"Social/Friends/Requests/Decline/{member_id}",
1412            auth=access_token,
1413        )
1414
1415    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1416        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1417        await self._request(
1418            RequestMethod.POST,
1419            f"Social/Friends/Remove/{member_id}",
1420            auth=access_token,
1421        )
1422
1423    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1424        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1425        await self._request(
1426            RequestMethod.POST,
1427            f"Social/Friends/Requests/Remove/{member_id}",
1428            auth=access_token,
1429        )
1430
1431    async def approve_all_pending_group_users(
1432        self,
1433        access_token: str,
1434        /,
1435        group_id: int,
1436        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1437    ) -> None:
1438        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1439        await self._request(
1440            RequestMethod.POST,
1441            f"GroupV2/{group_id}/Members/ApproveAll",
1442            auth=access_token,
1443            json={"message": str(message)},
1444        )
1445
1446    async def deny_all_pending_group_users(
1447        self,
1448        access_token: str,
1449        /,
1450        group_id: int,
1451        *,
1452        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1453    ) -> None:
1454        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1455        await self._request(
1456            RequestMethod.POST,
1457            f"GroupV2/{group_id}/Members/DenyAll",
1458            auth=access_token,
1459            json={"message": str(message)},
1460        )
1461
1462    async def add_optional_conversation(
1463        self,
1464        access_token: str,
1465        /,
1466        group_id: int,
1467        *,
1468        name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1469        security: typing.Literal[0, 1] = 0,
1470    ) -> None:
1471        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1472        payload = {"chatName": str(name), "chatSecurity": security}
1473        await self._request(
1474            RequestMethod.POST,
1475            f"GroupV2/{group_id}/OptionalConversations/Add",
1476            json=payload,
1477            auth=access_token,
1478        )
1479
1480    async def edit_optional_conversation(
1481        self,
1482        access_token: str,
1483        /,
1484        group_id: int,
1485        conversation_id: int,
1486        *,
1487        name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1488        security: typing.Literal[0, 1] = 0,
1489        enable_chat: bool = False,
1490    ) -> None:
1491        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1492        payload = {
1493            "chatEnabled": enable_chat,
1494            "chatName": str(name),
1495            "chatSecurity": security,
1496        }
1497        await self._request(
1498            RequestMethod.POST,
1499            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1500            json=payload,
1501            auth=access_token,
1502        )
1503
1504    async def transfer_item(
1505        self,
1506        access_token: str,
1507        /,
1508        item_id: int,
1509        item_hash: int,
1510        character_id: int,
1511        member_type: typedefs.IntAnd[enums.MembershipType],
1512        *,
1513        stack_size: int = 1,
1514        vault: bool = False,
1515    ) -> None:
1516        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1517        payload = {
1518            "characterId": character_id,
1519            "membershipType": int(member_type),
1520            "itemId": item_id,
1521            "itemReferenceHash": item_hash,
1522            "stackSize": stack_size,
1523            "transferToVault": vault,
1524        }
1525        await self._request(
1526            RequestMethod.POST,
1527            "Destiny2/Actions/Items/TransferItem",
1528            json=payload,
1529            auth=access_token,
1530        )
1531
1532    async def pull_item(
1533        self,
1534        access_token: str,
1535        /,
1536        item_id: int,
1537        item_hash: int,
1538        character_id: int,
1539        member_type: typedefs.IntAnd[enums.MembershipType],
1540        *,
1541        stack_size: int = 1,
1542        vault: bool = False,
1543    ) -> None:
1544        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1545        payload = {
1546            "characterId": character_id,
1547            "membershipType": int(member_type),
1548            "itemId": item_id,
1549            "itemReferenceHash": item_hash,
1550            "stackSize": stack_size,
1551            "transferToVault": vault,
1552        }
1553        await self._request(
1554            RequestMethod.POST,
1555            "Destiny2/Actions/Items/PullFromPostmaster",
1556            json=payload,
1557            auth=access_token,
1558        )
1559
1560    async def fetch_fireteams(
1561        self,
1562        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1563        *,
1564        platform: typedefs.IntAnd[
1565            fireteams.FireteamPlatform
1566        ] = fireteams.FireteamPlatform.ANY,
1567        language: typing.Union[
1568            fireteams.FireteamLanguage, str
1569        ] = fireteams.FireteamLanguage.ALL,
1570        date_range: typedefs.IntAnd[
1571            fireteams.FireteamDate
1572        ] = fireteams.FireteamDate.ALL,
1573        page: int = 0,
1574        slots_filter: int = 0,
1575    ) -> typedefs.JSONObject:
1576        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1577        resp = await self._request(
1578            RequestMethod.GET,
1579            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1580        )
1581        assert isinstance(resp, dict)
1582        return resp
1583
1584    async def fetch_avaliable_clan_fireteams(
1585        self,
1586        access_token: str,
1587        group_id: int,
1588        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1589        *,
1590        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1591        language: typing.Union[fireteams.FireteamLanguage, str],
1592        date_range: typedefs.IntAnd[
1593            fireteams.FireteamDate
1594        ] = fireteams.FireteamDate.ALL,
1595        page: int = 0,
1596        public_only: bool = False,
1597        slots_filter: int = 0,
1598    ) -> typedefs.JSONObject:
1599        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1600        resp = await self._request(
1601            RequestMethod.GET,
1602            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1603            json={"langFilter": str(language)},
1604            auth=access_token,
1605        )
1606        assert isinstance(resp, dict)
1607        return resp
1608
1609    async def fetch_clan_fireteam(
1610        self, access_token: str, fireteam_id: int, group_id: int
1611    ) -> typedefs.JSONObject:
1612        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1613        resp = await self._request(
1614            RequestMethod.GET,
1615            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1616            auth=access_token,
1617        )
1618        assert isinstance(resp, dict)
1619        return resp
1620
1621    async def fetch_my_clan_fireteams(
1622        self,
1623        access_token: str,
1624        group_id: int,
1625        *,
1626        include_closed: bool = True,
1627        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1628        language: typing.Union[fireteams.FireteamLanguage, str],
1629        filtered: bool = True,
1630        page: int = 0,
1631    ) -> typedefs.JSONObject:
1632        payload = {"groupFilter": filtered, "langFilter": str(language)}
1633        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1634        resp = await self._request(
1635            RequestMethod.GET,
1636            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1637            json=payload,
1638            auth=access_token,
1639        )
1640        assert isinstance(resp, dict)
1641        return resp
1642
1643    async def fetch_private_clan_fireteams(
1644        self, access_token: str, group_id: int, /
1645    ) -> int:
1646        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1647        resp = await self._request(
1648            RequestMethod.GET,
1649            f"Fireteam/Clan/{group_id}/ActiveCount",
1650            auth=access_token,
1651        )
1652        assert isinstance(resp, int)
1653        return resp
1654
1655    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1656        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1657        resp = await self._request(
1658            RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1659        )
1660        assert isinstance(resp, dict)
1661        return resp
1662
1663    async def search_entities(
1664        self, name: str, entity_type: str, *, page: int = 0
1665    ) -> typedefs.JSONObject:
1666        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1667        resp = await self._request(
1668            RequestMethod.GET,
1669            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1670            json={"page": page},
1671        )
1672        assert isinstance(resp, dict)
1673        return resp
1674
1675    async def fetch_unique_weapon_history(
1676        self,
1677        membership_id: int,
1678        character_id: int,
1679        membership_type: typedefs.IntAnd[enums.MembershipType],
1680    ) -> typedefs.JSONObject:
1681        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1682        resp = await self._request(
1683            RequestMethod.GET,
1684            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1685        )
1686        assert isinstance(resp, dict)
1687        return resp
1688
1689    async def fetch_item(
1690        self,
1691        member_id: int,
1692        item_id: int,
1693        membership_type: typedefs.IntAnd[enums.MembershipType],
1694        components: list[enums.ComponentType],
1695    ) -> typedefs.JSONObject:
1696        collector = _collect_components(components)
1697        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1698        resp = await self._request(
1699            RequestMethod.GET,
1700            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1701        )
1702        assert isinstance(resp, dict)
1703        return resp
1704
1705    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1706        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1707        resp = await self._request(
1708            RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/"
1709        )
1710        assert isinstance(resp, dict)
1711        return resp
1712
1713    async def fetch_available_locales(self) -> typedefs.JSONObject:
1714        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1715        resp = await self._request(
1716            RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/"
1717        )
1718        assert isinstance(resp, dict)
1719        return resp
1720
1721    async def fetch_common_settings(self) -> typedefs.JSONObject:
1722        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1723        resp = await self._request(RequestMethod.GET, "Settings")
1724        assert isinstance(resp, dict)
1725        return resp
1726
1727    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1728        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1729        resp = await self._request(RequestMethod.GET, "UserSystemOverrides")
1730        assert isinstance(resp, dict)
1731        return resp
1732
1733    async def fetch_global_alerts(
1734        self, *, include_streaming: bool = False
1735    ) -> typedefs.JSONArray:
1736        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1737        resp = await self._request(
1738            RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1739        )
1740        assert isinstance(resp, list)
1741        return resp
1742
1743    async def awainitialize_request(
1744        self,
1745        access_token: str,
1746        type: typing.Literal[0, 1],
1747        membership_type: typedefs.IntAnd[enums.MembershipType],
1748        /,
1749        *,
1750        affected_item_id: typing.Optional[int] = None,
1751        character_id: typing.Optional[int] = None,
1752    ) -> typedefs.JSONObject:
1753        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1754
1755        body = {"type": type, "membershipType": int(membership_type)}
1756
1757        if affected_item_id is not None:
1758            body["affectedItemId"] = affected_item_id
1759
1760        if character_id is not None:
1761            body["characterId"] = character_id
1762
1763        resp = await self._request(
1764            RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1765        )
1766        assert isinstance(resp, dict)
1767        return resp
1768
1769    async def awaget_action_token(
1770        self, access_token: str, correlation_id: str, /
1771    ) -> typedefs.JSONObject:
1772        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1773        resp = await self._request(
1774            RequestMethod.POST,
1775            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1776            auth=access_token,
1777        )
1778        assert isinstance(resp, dict)
1779        return resp
1780
1781    async def awa_provide_authorization_result(
1782        self,
1783        access_token: str,
1784        selection: int,
1785        correlation_id: str,
1786        nonce: collections.MutableSequence[typing.Union[str, bytes]],
1787    ) -> int:
1788        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1789
1790        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1791
1792        resp = await self._request(
1793            RequestMethod.POST,
1794            "Destiny2/Awa/AwaProvideAuthorizationResult",
1795            json=body,
1796            auth=access_token,
1797        )
1798        assert isinstance(resp, int)
1799        return resp
1800
1801    async def fetch_vendors(
1802        self,
1803        access_token: str,
1804        character_id: int,
1805        membership_id: int,
1806        membership_type: typedefs.IntAnd[enums.MembershipType],
1807        /,
1808        components: list[enums.ComponentType],
1809        filter: typing.Optional[int] = None,
1810    ) -> typedefs.JSONObject:
1811        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1812        components_ = _collect_components(components)
1813        route = (
1814            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1815            f"/Character/{character_id}/Vendors/?components={components_}"
1816        )
1817
1818        if filter is not None:
1819            route = route + f"&filter={filter}"
1820
1821        resp = await self._request(
1822            RequestMethod.GET,
1823            route,
1824            auth=access_token,
1825        )
1826        assert isinstance(resp, dict)
1827        return resp
1828
1829    async def fetch_vendor(
1830        self,
1831        access_token: str,
1832        character_id: int,
1833        membership_id: int,
1834        membership_type: typedefs.IntAnd[enums.MembershipType],
1835        vendor_hash: int,
1836        /,
1837        components: list[enums.ComponentType],
1838    ) -> typedefs.JSONObject:
1839        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1840        components_ = _collect_components(components)
1841        resp = await self._request(
1842            RequestMethod.GET,
1843            (
1844                f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1845                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1846            ),
1847            auth=access_token,
1848        )
1849        assert isinstance(resp, dict)
1850        return resp
1851
1852    async def fetch_application_api_usage(
1853        self,
1854        access_token: str,
1855        application_id: int,
1856        /,
1857        *,
1858        start: typing.Optional[datetime.datetime] = None,
1859        end: typing.Optional[datetime.datetime] = None,
1860    ) -> typedefs.JSONObject:
1861        end_date, start_date = time.parse_date_range(end, start)
1862        resp = await self._request(
1863            RequestMethod.GET,
1864            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1865            auth=access_token,
1866        )
1867        assert isinstance(resp, dict)
1868        return resp
1869
1870    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1871        resp = await self._request(RequestMethod.GET, "App/FirstParty")
1872        assert isinstance(resp, list)
1873        return resp
1874
1875    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1876        resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/")
1877        assert isinstance(resp, dict)
1878        return resp
1879
1880    async def fetch_content_by_id(
1881        self, id: int, locale: str, /, *, head: bool = False
1882    ) -> typedefs.JSONObject:
1883        resp = await self._request(
1884            RequestMethod.GET,
1885            f"Content/GetContentById/{id}/{locale}/",
1886            json={"head": head},
1887        )
1888        assert isinstance(resp, dict)
1889        return resp
1890
1891    async def fetch_content_by_tag_and_type(
1892        self, locale: str, tag: str, type: str, *, head: bool = False
1893    ) -> typedefs.JSONObject:
1894        resp = await self._request(
1895            RequestMethod.GET,
1896            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1897            json={"head": head},
1898        )
1899        assert isinstance(resp, dict)
1900        return resp
1901
1902    async def search_content_with_text(
1903        self,
1904        locale: str,
1905        /,
1906        content_type: str,
1907        search_text: str,
1908        tag: str,
1909        *,
1910        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1911        source: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1912    ) -> typedefs.JSONObject:
1913        body: typedefs.JSONObject = {}
1914
1915        body["ctype"] = content_type
1916        body["searchtext"] = search_text
1917        body["tag"] = tag
1918
1919        if page is not undefined.UNDEFINED:
1920            body["currentpage"] = page
1921        else:
1922            body["currentpage"] = 1
1923
1924        if source is not undefined.UNDEFINED:
1925            body["source"] = source
1926        else:
1927            source = ""
1928        resp = await self._request(
1929            RequestMethod.GET, f"Content/Search/{locale}/", json=body
1930        )
1931        assert isinstance(resp, dict)
1932        return resp
1933
1934    async def search_content_by_tag_and_type(
1935        self,
1936        locale: str,
1937        tag: str,
1938        type: str,
1939        *,
1940        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1941    ) -> typedefs.JSONObject:
1942        body: typedefs.JSONObject = {}
1943        body["currentpage"] = 1 if page is undefined.UNDEFINED else page
1944        resp = await self._request(
1945            RequestMethod.GET,
1946            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
1947            json=body,
1948        )
1949        assert isinstance(resp, dict)
1950        return resp
1951
1952    async def search_help_articles(
1953        self, text: str, size: str, /
1954    ) -> typedefs.JSONObject:
1955        resp = await self._request(
1956            RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/"
1957        )
1958        assert isinstance(resp, dict)
1959        return resp
1960
1961    async def fetch_topics_page(
1962        self,
1963        category_filter: int,
1964        group: int,
1965        date_filter: int,
1966        sort: typing.Union[str, bytes],
1967        *,
1968        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1969        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED,
1970        tag_filter: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1971    ) -> typedefs.JSONObject:
1972        body: typedefs.JSONObject = {}
1973        if locales is not undefined.UNDEFINED:
1974            body["locales"] = ",".join(str(locales))
1975        else:
1976            body["locales"] = ",".join([])
1977
1978        if tag_filter is not undefined.UNDEFINED:
1979            body["tagstring"] = tag_filter
1980        else:
1981            body["tagstring"] = ""
1982
1983        page = 0 if page is not undefined.UNDEFINED else page
1984
1985        resp = await self._request(
1986            RequestMethod.GET,
1987            f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/",
1988            json=body,
1989        )
1990        assert isinstance(resp, dict)
1991        return resp
1992
1993    async def fetch_core_topics_page(
1994        self,
1995        category_filter: int,
1996        date_filter: int,
1997        sort: typing.Union[str, bytes],
1998        *,
1999        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
2000        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED,
2001    ) -> typedefs.JSONObject:
2002        body: typedefs.JSONObject = {}
2003
2004        if locales is not undefined.UNDEFINED:
2005            body["locales"] = ",".join(str(locales))
2006        else:
2007            body["locales"] = ",".join([])
2008
2009        resp = await self._request(
2010            RequestMethod.GET,
2011            f"Forum/GetCoreTopicsPaged/{0 if page is undefined.UNDEFINED else page}"
2012            f"/{sort!s}/{date_filter}/{category_filter}/",
2013            json=body,
2014        )
2015        assert isinstance(resp, dict)
2016        return resp
2017
2018    async def fetch_posts_threaded_page(
2019        self,
2020        parent_post: bool,
2021        page: int,
2022        page_size: int,
2023        parent_post_id: int,
2024        reply_size: int,
2025        root_thread_mode: bool,
2026        sort_mode: int,
2027        show_banned: typing.Optional[str] = None,
2028    ) -> typedefs.JSONObject:
2029        resp = await self._request(
2030            RequestMethod.GET,
2031            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
2032            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
2033            json={"showbanned": show_banned},
2034        )
2035        assert isinstance(resp, dict)
2036        return resp
2037
2038    async def fetch_posts_threaded_page_from_child(
2039        self,
2040        child_id: bool,
2041        page: int,
2042        page_size: int,
2043        reply_size: int,
2044        root_thread_mode: bool,
2045        sort_mode: int,
2046        show_banned: typing.Optional[str] = None,
2047    ) -> typedefs.JSONObject:
2048        resp = await self._request(
2049            RequestMethod.GET,
2050            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
2051            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
2052            json={"showbanned": show_banned},
2053        )
2054        assert isinstance(resp, dict)
2055        return resp
2056
2057    async def fetch_post_and_parent(
2058        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2059    ) -> typedefs.JSONObject:
2060        resp = await self._request(
2061            RequestMethod.GET,
2062            f"Forum/GetPostAndParent/{child_id}/",
2063            json={"showbanned": show_banned},
2064        )
2065        assert isinstance(resp, dict)
2066        return resp
2067
2068    async def fetch_posts_and_parent_awaiting(
2069        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2070    ) -> typedefs.JSONObject:
2071        resp = await self._request(
2072            RequestMethod.GET,
2073            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2074            json={"showbanned": show_banned},
2075        )
2076        assert isinstance(resp, dict)
2077        return resp
2078
2079    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2080        resp = await self._request(
2081            RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/"
2082        )
2083        assert isinstance(resp, int)
2084        return resp
2085
2086    async def fetch_forum_tag_suggestions(
2087        self, partial_tag: str, /
2088    ) -> typedefs.JSONObject:
2089        resp = await self._request(
2090            RequestMethod.GET,
2091            "Forum/GetForumTagSuggestions/",
2092            json={"partialtag": partial_tag},
2093        )
2094        assert isinstance(resp, dict)
2095        return resp
2096
2097    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2098        resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/")
2099        assert isinstance(resp, dict)
2100        return resp
2101
2102    async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray:
2103        resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/")
2104        assert isinstance(resp, list)
2105        return resp
2106
2107    async def fetch_recommended_groups(
2108        self,
2109        accecss_token: str,
2110        /,
2111        *,
2112        date_range: int = 0,
2113        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
2114    ) -> typedefs.JSONArray:
2115        resp = await self._request(
2116            RequestMethod.POST,
2117            f"GroupV2/Recommended/{int(group_type)}/{date_range}/",
2118            auth=accecss_token,
2119        )
2120        assert isinstance(resp, list)
2121        return resp
2122
2123    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2124        resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/")
2125        assert isinstance(resp, dict)
2126        return resp
2127
2128    async def fetch_user_clan_invite_setting(
2129        self,
2130        access_token: str,
2131        /,
2132        membership_type: typedefs.IntAnd[enums.MembershipType],
2133    ) -> bool:
2134        resp = await self._request(
2135            RequestMethod.GET,
2136            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2137            auth=access_token,
2138        )
2139        assert isinstance(resp, bool)
2140        return resp
2141
2142    async def fetch_banned_group_members(
2143        self, access_token: str, group_id: int, /, *, page: int = 1
2144    ) -> typedefs.JSONObject:
2145        resp = await self._request(
2146            RequestMethod.GET,
2147            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2148            auth=access_token,
2149        )
2150        assert isinstance(resp, dict)
2151        return resp
2152
2153    async def fetch_pending_group_memberships(
2154        self, access_token: str, group_id: int, /, *, current_page: int = 1
2155    ) -> typedefs.JSONObject:
2156        resp = await self._request(
2157            RequestMethod.GET,
2158            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2159            auth=access_token,
2160        )
2161        assert isinstance(resp, dict)
2162        return resp
2163
2164    async def fetch_invited_group_memberships(
2165        self, access_token: str, group_id: int, /, *, current_page: int = 1
2166    ) -> typedefs.JSONObject:
2167        resp = await self._request(
2168            RequestMethod.GET,
2169            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2170            auth=access_token,
2171        )
2172        assert isinstance(resp, dict)
2173        return resp
2174
2175    async def invite_member_to_group(
2176        self,
2177        access_token: str,
2178        /,
2179        group_id: int,
2180        membership_id: int,
2181        membership_type: typedefs.IntAnd[enums.MembershipType],
2182        *,
2183        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
2184    ) -> typedefs.JSONObject:
2185        resp = await self._request(
2186            RequestMethod.POST,
2187            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2188            auth=access_token,
2189            json={"message": str(message)},
2190        )
2191        assert isinstance(resp, dict)
2192        return resp
2193
2194    async def cancel_group_member_invite(
2195        self,
2196        access_token: str,
2197        /,
2198        group_id: int,
2199        membership_id: int,
2200        membership_type: typedefs.IntAnd[enums.MembershipType],
2201    ) -> typedefs.JSONObject:
2202        resp = await self._request(
2203            RequestMethod.POST,
2204            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2205            auth=access_token,
2206        )
2207        assert isinstance(resp, dict)
2208        return resp
2209
2210    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2211        resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/")
2212        assert isinstance(resp, dict)
2213        return resp
2214
2215    async def fetch_historical_stats(
2216        self,
2217        character_id: int,
2218        membership_id: int,
2219        membership_type: typedefs.IntAnd[enums.MembershipType],
2220        day_start: datetime.datetime,
2221        day_end: datetime.datetime,
2222        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2223        modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]],
2224        *,
2225        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2226    ) -> typedefs.JSONObject:
2227        end, start = time.parse_date_range(day_end, day_start)
2228        resp = await self._request(
2229            RequestMethod.GET,
2230            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2231            json={
2232                "dayend": end,
2233                "daystart": start,
2234                "groups": [str(int(group)) for group in groups],
2235                "modes": [str(int(mode)) for mode in modes],
2236                "periodType": int(period_type),
2237            },
2238        )
2239        assert isinstance(resp, dict)
2240        return resp
2241
2242    async def fetch_historical_stats_for_account(
2243        self,
2244        membership_id: int,
2245        membership_type: typedefs.IntAnd[enums.MembershipType],
2246        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2247    ) -> typedefs.JSONObject:
2248        resp = await self._request(
2249            RequestMethod.GET,
2250            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2251            json={"groups": [str(int(group)) for group in groups]},
2252        )
2253        assert isinstance(resp, dict)
2254        return resp
2255
2256    async def fetch_aggregated_activity_stats(
2257        self,
2258        character_id: int,
2259        membership_id: int,
2260        membership_type: typedefs.IntAnd[enums.MembershipType],
2261        /,
2262    ) -> typedefs.JSONObject:
2263        resp = await self._request(
2264            RequestMethod.GET,
2265            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2266            f"Character/{character_id}/Stats/AggregateActivityStats/",
2267        )
2268        assert isinstance(resp, dict)
2269        return resp
2270
2271    async def equip_loadout(
2272        self,
2273        access_token: str,
2274        /,
2275        loadout_index: int,
2276        character_id: int,
2277        membership_type: typedefs.IntAnd[enums.MembershipType],
2278    ) -> None:
2279        response = await self._request(
2280            RequestMethod.POST,
2281            "Destiny2/Actions/Loadouts/EquipLoadout/",
2282            json={
2283                "loadoutIndex": loadout_index,
2284                "characterId": character_id,
2285                "membership_type": int(membership_type),
2286            },
2287            auth=access_token,
2288        )
2289        assert isinstance(response, int)
2290
2291    async def snapshot_loadout(
2292        self,
2293        access_token: str,
2294        /,
2295        loadout_index: int,
2296        character_id: int,
2297        membership_type: typedefs.IntAnd[enums.MembershipType],
2298        *,
2299        color_hash: typing.Optional[int] = None,
2300        icon_hash: typing.Optional[int] = None,
2301        name_hash: typing.Optional[int] = None,
2302    ) -> None:
2303        response = await self._request(
2304            RequestMethod.POST,
2305            "Destiny2/Actions/Loadouts/SnapshotLoadout/",
2306            auth=access_token,
2307            json={
2308                "colorHash": color_hash,
2309                "iconHash": icon_hash,
2310                "nameHash": name_hash,
2311                "loadoutIndex": loadout_index,
2312                "characterId": character_id,
2313                "membershipType": int(membership_type),
2314            },
2315        )
2316        assert isinstance(response, int)
2317
2318    async def update_loadout(
2319        self,
2320        access_token: str,
2321        /,
2322        loadout_index: int,
2323        character_id: int,
2324        membership_type: typedefs.IntAnd[enums.MembershipType],
2325        *,
2326        color_hash: typing.Optional[int] = None,
2327        icon_hash: typing.Optional[int] = None,
2328        name_hash: typing.Optional[int] = None,
2329    ) -> None:
2330        response = await self._request(
2331            RequestMethod.POST,
2332            "Destiny2/Actions/Loadouts/UpdateLoadoutIdentifiers/",
2333            auth=access_token,
2334            json={
2335                "colorHash": color_hash,
2336                "iconHash": icon_hash,
2337                "nameHash": name_hash,
2338                "loadoutIndex": loadout_index,
2339                "characterId": character_id,
2340                "membershipType": int(membership_type),
2341            },
2342        )
2343        assert isinstance(response, int)
2344
2345    async def clear_loadout(
2346        self,
2347        access_token: str,
2348        /,
2349        loadout_index: int,
2350        character_id: int,
2351        membership_type: typedefs.IntAnd[enums.MembershipType],
2352    ) -> None:
2353        response = await self._request(
2354            RequestMethod.POST,
2355            "Destiny2/Actions/Loadouts/ClearLoadout/",
2356            json={
2357                "loadoutIndex": loadout_index,
2358                "characterId": character_id,
2359                "membership_type": int(membership_type),
2360            },
2361            auth=access_token,
2362        )
2363        assert isinstance(response, int)

A RESTful client implementation for Bungie's API.

This client is designed to only make HTTP requests and return JSON objects to provide RESTful functionality.

This client is also used within aiobungie.Client which deserialize those returned JSON objects using the factory into Pythonic data classes objects which provide Python functionality.

Example
import aiobungie

async def main():
    async with aiobungie.RESTClient("TOKEN") as rest_client:
        req = await rest_client.fetch_clan_members(4389205)
        clan_members = req['results']
        for member in clan_members:
            for k, v in member['destinyUserInfo'].items():
                print(k, v)
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • enable_debugging (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | TRACE: This will log the response headers along with the minimal information.
RESTClient( token: str, /, *, client_secret: Optional[str] = None, client_id: Optional[int] = None, client_session: Optional[aiohttp.client.ClientSession] = None, max_retries: int = 4, enable_debugging: Union[Literal['TRACE'], bool, int] = False)
371    def __init__(
372        self,
373        token: str,
374        /,
375        *,
376        client_secret: typing.Optional[str] = None,
377        client_id: typing.Optional[int] = None,
378        client_session: typing.Optional[aiohttp.ClientSession] = None,
379        max_retries: int = 4,
380        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
381    ) -> None:
382        self._session: typing.Optional[aiohttp.ClientSession] = client_session
383        self._lock: typing.Optional[asyncio.Lock] = None
384        self._client_secret = client_secret
385        self._client_id = client_id
386        self._token: str = token
387        self._max_retries = max_retries
388        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
389
390        self._set_debug_level(enable_debugging)
client_id: Optional[int]

Return the client id of this REST client if provided, Otherwise None.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

A mutable mapping storage for the user's needs.

This mapping is useful for storing any kind of data that the user may need.

Example
import aiobungie

client = aiobungie.RESTClient(…)

async with client:
    # Fetch auth tokens and store them
    client.metadata["tokens"] = await client.fetch_access_token("code")

# Some other time.
async with client:
    # Retrieve the tokens
    tokens: aiobungie.OAuth2Response = client.metadata["tokens"]

    # Use them to fetch your user.
    user = await client.fetch_current_user_memberships(tokens.access_token)
is_alive: bool

Returns True if the REST client is alive and False otherwise.

@typing.final
async def close(self) -> None:
404    @typing.final
405    async def close(self) -> None:
406        if self._session is None:
407            raise RuntimeError("REST client is not running.")
408
409        await self._session.close()
410        self._session = None

Close this REST client session if it was acquired.

This method is automatically called when using async with contextmanager.

Raises
  • RuntimeError: If the client is already closed.
@typing.final
def open(self) -> None:
412    @typing.final
413    def open(self) -> None:
414        """Open a new client session. This is called internally with contextmanager usage."""
415        if self._session:
416            raise RuntimeError("Cannot open REST client when it's already open.")
417
418        self._session = aiohttp.ClientSession(
419            connector=aiohttp.TCPConnector(ssl=False),
420            raise_for_status=False,
421            timeout=aiohttp.ClientTimeout(total=30.0),
422        )

Open a new client session. This is called internally with contextmanager usage.

@typing.final
def enable_debugging( self, level: Union[Literal['TRACE'], bool, int] = False, file: Union[pathlib.Path, str, NoneType] = None, /) -> None:
424    @typing.final
425    def enable_debugging(
426        self,
427        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
428        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
429        /,
430    ) -> None:
431        self._set_debug_level(level, file)

Enables debugging for the REST calls.

Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | TRACE: This will log the response headers along with the minimal information.
Parameters
  • level (str | bool | int): The level of debugging to enable.
  • file (pathlib.Path | str | None): The file path to write the debug logs to. If provided.
@typing.final
async def static_request( self, method: Union[RequestMethod, str], path: str, *, auth: Optional[str] = None, json: Optional[dict[str, Any]] = None) -> Union[dict[str, Any], list[Any], bytes, int, bool, NoneType]:
433    @typing.final
434    async def static_request(
435        self,
436        method: typing.Union[RequestMethod, str],
437        path: str,
438        *,
439        auth: typing.Optional[str] = None,
440        json: typing.Optional[dict[str, typing.Any]] = None,
441    ) -> ResponseSig:
442        return await self._request(method, path, auth=auth, json=json)

Perform an HTTP request given a valid Bungie endpoint.

Parameters
  • method (RequestMethod | str): The request method, This may be GET, POST, PUT, etc.
  • path (str): The Bungie endpoint or path. A path must look something like this Destiny2/3/Profile/46111239123/...
  • auth (str | None): An optional bearer token for methods that requires OAuth2 Authorization header.
  • json (dict[str, typing.Any] | None): An optional JSON data to include in the request.
Returns
  • aiobungie.rest.ResponseSig: The response payload.
@typing.final
def build_oauth2_url( self, client_id: Optional[int] = None) -> Optional[aiobungie.builders.OAuthURL]:
444    @typing.final
445    def build_oauth2_url(
446        self, client_id: typing.Optional[int] = None
447    ) -> typing.Optional[builders.OAuthURL]:
448        client_id = client_id or self._client_id
449        if client_id is None:
450            return None
451
452        return builders.OAuthURL(client_id=client_id)

Builds an OAuth2 URL using the provided user REST/Base client secret/id.

You can't get the complete string URL by using .compile() method.

Parameters
  • client_id (int | None): An optional client id to provide, If left None it will roll back to the id passed to the RESTClient, If both is None this method will return None.
Returns
async def fetch_oauth2_tokens(self, code: str, /) -> aiobungie.builders.OAuth2Response:
660    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
661        if not isinstance(self._client_secret, (str, int)):
662            raise TypeError(
663                "Expected (str, int) for client secret "
664                f"but got {type(self._client_secret).__name__}"  # type: ignore
665            )
666
667        headers = {
668            "client_secret": self._client_secret,
669        }
670
671        data = (
672            f"grant_type=authorization_code&code={code}"
673            f"&client_id={self._client_id}&client_secret={self._client_secret}"
674        )
675
676        response = await self._request(
677            RequestMethod.POST, "", headers=headers, data=data, oauth2=True
678        )
679        assert isinstance(response, dict)
680        return builders.OAuth2Response.build_response(response)

Makes a POST request and fetch the OAuth2 access_token and refresh token.

Parameters
  • code (str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
Raises
async def refresh_access_token(self, refresh_token: str, /) -> aiobungie.builders.OAuth2Response:
682    async def refresh_access_token(
683        self, refresh_token: str, /
684    ) -> builders.OAuth2Response:
685        if not isinstance(self._client_secret, (int, str)):
686            raise TypeError(
687                f"Expected (str, int) for client secret but got {type(self._client_secret).__name__}"  # type: ignore
688            )
689
690        data = {
691            "grant_type": "refresh_token",
692            "refresh_token": refresh_token,
693            "client_id": self._client_id,
694            "client_secret": self._client_secret,
695            "Content-Type": "application/x-www-form-urlencoded",
696        }
697
698        response = await self._request(RequestMethod.POST, "", data=data, oauth2=True)
699        assert isinstance(response, dict)
700        return builders.OAuth2Response.build_response(response)

Refresh OAuth2 access token given its refresh token.

Parameters
  • refresh_token (str): The refresh token.
Returns
async def fetch_bungie_user(self, id: int) -> dict[str, typing.Any]:
702    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
703        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
704        resp = await self._request(
705            RequestMethod.GET, f"User/GetBungieNetUserById/{id}/"
706        )
707        assert isinstance(resp, dict)
708        return resp

Fetch a Bungie user by their id.

Parameters
  • id (int): The user id.
Returns
Raises
async def fetch_user_themes(self) -> list[typing.Any]:
710    async def fetch_user_themes(self) -> typedefs.JSONArray:
711        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
712        resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/")
713        assert isinstance(resp, list)
714        return resp

Fetch all available user themes.

Returns
async def fetch_membership_from_id( self, id: int, type: Union[int, MembershipType] = <MembershipType.NONE: 0>, /) -> dict[str, typing.Any]:
716    async def fetch_membership_from_id(
717        self,
718        id: int,
719        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
720        /,
721    ) -> typedefs.JSONObject:
722        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
723        resp = await self._request(
724            RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}"
725        )
726        assert isinstance(resp, dict)
727        return resp

Fetch Bungie user's memberships from their id.

Parameters
Returns
Raises
async def fetch_player( self, name: str, code: int, type: Union[int, MembershipType] = <MembershipType.ALL: -1>, /) -> list[typing.Any]:
729    async def fetch_player(
730        self,
731        name: str,
732        code: int,
733        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
734        /,
735    ) -> typedefs.JSONArray:
736        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
737        resp = await self._request(
738            RequestMethod.POST,
739            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
740            json={"displayName": name, "displayNameCode": code},
741        )
742        assert isinstance(resp, list)
743        return resp

Fetch a Destiny 2 Player.

Parameters
Returns
Raises
async def search_users(self, name: str, /) -> dict[str, typing.Any]:
745    async def search_users(self, name: str, /) -> typedefs.JSONObject:
746        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
747        resp = await self._request(
748            RequestMethod.POST,
749            "User/Search/GlobalName/0",
750            json={"displayNamePrefix": name},
751        )
752        assert isinstance(resp, dict)
753        return resp

Search for users by their global name and return all users who share this name.

Parameters
  • name (str): The user name.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: Optional[str] = None) -> dict[str, typing.Any]:
755    async def fetch_clan_from_id(
756        self, id: int, /, access_token: typing.Optional[str] = None
757    ) -> typedefs.JSONObject:
758        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
759        resp = await self._request(
760            RequestMethod.GET, f"GroupV2/{id}", auth=access_token
761        )
762        assert isinstance(resp, dict)
763        return resp

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Other Parameters
  • access_token (typing.Optional[str]): An optional access token to make the request with.

    If the token was bound to a member of the clan, This field aiobungie.crates.Clan.current_user_membership will be available and will return the membership of the user who made this request.

Returns
Raises
async def fetch_clan( self, name: str, /, access_token: Optional[str] = None, *, type: Union[int, GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
765    async def fetch_clan(
766        self,
767        name: str,
768        /,
769        access_token: typing.Optional[str] = None,
770        *,
771        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
772    ) -> typedefs.JSONObject:
773        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
774        resp = await self._request(
775            RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
776        )
777        assert isinstance(resp, dict)
778        return resp

Fetch a Clan by its name. This method will return the first clan found with given name name.

Parameters
  • name (str): The clan name.
Other Parameters
Returns
Raises
async def fetch_clan_admins(self, clan_id: int, /) -> dict[str, typing.Any]:
780    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
781        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
782        resp = await self._request(
783            RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/"
784        )
785        assert isinstance(resp, dict)
786        return resp

Fetch the admins and founder members of the clan.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_clan_conversations(self, clan_id: int, /) -> list[typing.Any]:
788    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
789        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
790        resp = await self._request(
791            RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/"
792        )
793        assert isinstance(resp, list)
794        return resp

Fetch a clan's conversations.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_application(self, appid: int, /) -> dict[str, typing.Any]:
796    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
797        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
798        resp = await self._request(RequestMethod.GET, f"App/Application/{appid}")
799        assert isinstance(resp, dict)
800        return resp

Fetch a Bungie Application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_character( self, member_id: int, membership_type: Union[int, MembershipType], character_id: int, components: list[ComponentType], auth: Optional[str] = None) -> dict[str, typing.Any]:
802    async def fetch_character(
803        self,
804        member_id: int,
805        membership_type: typedefs.IntAnd[enums.MembershipType],
806        character_id: int,
807        components: list[enums.ComponentType],
808        auth: typing.Optional[str] = None,
809    ) -> typedefs.JSONObject:
810        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
811        collector = _collect_components(components)
812        response = await self._request(
813            RequestMethod.GET,
814            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
815            f"Character/{character_id}/?components={collector}",
816            auth=auth,
817        )
818        assert isinstance(response, dict)
819        return response

Fetch a Destiny 2 player's characters.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_activities( self, member_id: int, character_id: int, mode: Union[int, GameMode], membership_type: Union[int, MembershipType] = <MembershipType.ALL: -1>, *, page: int = 0, limit: int = 1) -> dict[str, typing.Any]:
821    async def fetch_activities(
822        self,
823        member_id: int,
824        character_id: int,
825        mode: typedefs.IntAnd[enums.GameMode],
826        membership_type: typedefs.IntAnd[
827            enums.MembershipType
828        ] = enums.MembershipType.ALL,
829        *,
830        page: int = 0,
831        limit: int = 1,
832    ) -> typedefs.JSONObject:
833        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
834        resp = await self._request(
835            RequestMethod.GET,
836            f"Destiny2/{int(membership_type)}/Account/"
837            f"{member_id}/Character/{character_id}/Stats/Activities"
838            f"/?mode={int(mode)}&count={limit}&page={page}",
839        )
840        assert isinstance(resp, dict)
841        return resp

Fetch a Destiny 2 activity for the specified user id and character.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve.
  • mode (aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
  • membership_type (aiobungie.typedefs.IntAnd[MembershipType]): The Member ship type, if nothing was passed than it will return all.
  • page (int): The page number. Default to 1
  • limit (int): Limit the returned result. Default to 1
Returns
Raises
async def fetch_vendor_sales(self) -> dict[str, typing.Any]:
843    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
844        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
845        resp = await self._request(
846            RequestMethod.GET,
847            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
848        )
849        assert isinstance(resp, dict)
850        return resp
async def fetch_profile( self, membership_id: int, type: Union[int, MembershipType], components: list[ComponentType], auth: Optional[str] = None) -> dict[str, typing.Any]:
852    async def fetch_profile(
853        self,
854        membership_id: int,
855        type: typedefs.IntAnd[enums.MembershipType],
856        components: list[enums.ComponentType],
857        auth: typing.Optional[str] = None,
858    ) -> typedefs.JSONObject:
859        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
860        collector = _collect_components(components)
861        response = await self._request(
862            RequestMethod.GET,
863            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
864            auth=auth,
865        )
866        assert isinstance(response, dict)
867        return response

Fetch a bungie profile.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_entity(self, type: str, hash: int) -> dict[str, typing.Any]:
869    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
870        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
871        response = await self._request(
872            RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}"
873        )
874        assert isinstance(response, dict)
875        return response

Fetch a Destiny definition item given its type and hash.

Parameters
  • type (str): Entity's type definition.
  • hash (int): Entity's hash.
Returns
async def fetch_inventory_item(self, hash: int, /) -> dict[str, typing.Any]:
877    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
878        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
879        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
880        assert isinstance(resp, dict)
881        return resp

Fetch a Destiny inventory item entity given a its hash.

Parameters
  • hash (int): Entity's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> dict[str, typing.Any]:
883    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
884        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
885        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
886        assert isinstance(resp, dict)
887        return resp

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def fetch_groups_for_member( self, member_id: int, member_type: Union[int, MembershipType], /, *, filter: int = 0, group_type: Union[int, GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
889    async def fetch_groups_for_member(
890        self,
891        member_id: int,
892        member_type: typedefs.IntAnd[enums.MembershipType],
893        /,
894        *,
895        filter: int = 0,
896        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
897    ) -> typedefs.JSONObject:
898        resp = await self._request(
899            RequestMethod.GET,
900            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
901        )
902        assert isinstance(resp, dict)
903        return resp

Fetch the information about the groups for a member.

Parameters
Other Parameters
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: Union[int, MembershipType], /, *, filter: int = 0, group_type: Union[int, GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
905    async def fetch_potential_groups_for_member(
906        self,
907        member_id: int,
908        member_type: typedefs.IntAnd[enums.MembershipType],
909        /,
910        *,
911        filter: int = 0,
912        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
913    ) -> typedefs.JSONObject:
914        resp = await self._request(
915            RequestMethod.GET,
916            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
917        )
918        assert isinstance(resp, dict)
919        return resp

Get information about the groups that a given member has applied to or been invited to.

Parameters
Other Parameters
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: Optional[str] = None, type: Union[int, MembershipType] = <MembershipType.NONE: 0>) -> dict[str, typing.Any]:
921    async def fetch_clan_members(
922        self,
923        clan_id: int,
924        /,
925        *,
926        name: typing.Optional[str] = None,
927        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
928    ) -> typedefs.JSONObject:
929        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
930        resp = await self._request(
931            RequestMethod.GET,
932            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
933        )
934        assert isinstance(resp, dict)
935        return resp

Fetch all Bungie Clan members.

Parameters
  • clan_id (builsins.int): The clans id
Other Parameters
Returns
Raises
async def fetch_hardlinked_credentials( self, credential: int, type: Union[int, CredentialType] = <CredentialType.STEAMID: 12>, /) -> dict[str, typing.Any]:
937    async def fetch_hardlinked_credentials(
938        self,
939        credential: int,
940        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
941        /,
942    ) -> typedefs.JSONObject:
943        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
944        resp = await self._request(
945            RequestMethod.GET,
946            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
947        )
948        assert isinstance(resp, dict)
949        return resp

Gets any hard linked membership given a credential.

Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
Returns
async def fetch_user_credentials(self, access_token: str, membership_id: int, /) -> list[typing.Any]:
951    async def fetch_user_credentials(
952        self, access_token: str, membership_id: int, /
953    ) -> typedefs.JSONArray:
954        resp = await self._request(
955            RequestMethod.GET,
956            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
957            auth=access_token,
958        )
959        assert isinstance(resp, list)
960        return resp

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def insert_socket_plug( self, action_token: str, /, instance_id: int, plug: Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]], character_id: int, membership_type: Union[int, MembershipType]) -> dict[str, typing.Any]:
962    async def insert_socket_plug(
963        self,
964        action_token: str,
965        /,
966        instance_id: int,
967        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
968        character_id: int,
969        membership_type: typedefs.IntAnd[enums.MembershipType],
970    ) -> typedefs.JSONObject:
971        if isinstance(plug, builders.PlugSocketBuilder):
972            plug = plug.collect()
973
974        body = {
975            "actionToken": action_token,
976            "itemInstanceId": instance_id,
977            "plug": plug,
978            "characterId": character_id,
979            "membershipType": int(membership_type),
980        }
981        resp = await self._request(
982            RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
983        )
984        assert isinstance(resp, dict)
985        return resp

Insert a plug into a socketed item.

OAuth2: AdvancedWriteActions scope is required

Parameters
  • action_token (str): Action token provided by the AwaGetActionToken API call.
  • instance_id (int): The item instance id that's plug inserted.
  • plug (typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType] The membership type.

Returns
Raises
async def insert_socket_plug_free( self, access_token: str, /, instance_id: int, plug: Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]], character_id: int, membership_type: Union[int, MembershipType]) -> dict[str, typing.Any]:
 987    async def insert_socket_plug_free(
 988        self,
 989        access_token: str,
 990        /,
 991        instance_id: int,
 992        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
 993        character_id: int,
 994        membership_type: typedefs.IntAnd[enums.MembershipType],
 995    ) -> typedefs.JSONObject:
 996        if isinstance(plug, builders.PlugSocketBuilder):
 997            plug = plug.collect()
 998
 999        body = {
1000            "itemInstanceId": instance_id,
1001            "plug": plug,
1002            "characterId": character_id,
1003            "membershipType": int(membership_type),
1004        }
1005        resp = await self._request(
1006            RequestMethod.POST,
1007            "Destiny2/Actions/Items/InsertSocketPlugFree",
1008            json=body,
1009            auth=access_token,
1010        )
1011        assert isinstance(resp, dict)
1012        return resp

Insert a plug into a socketed item. This doesn't require an Action token.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • instance_id (int): The item instance id that's plug inserted.
  • plug (typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType] The membership type.

Returns
Raises
async def set_item_lock_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: Union[int, MembershipType]) -> int:
1014    async def set_item_lock_state(
1015        self,
1016        access_token: str,
1017        state: bool,
1018        /,
1019        item_id: int,
1020        character_id: int,
1021        membership_type: typedefs.IntAnd[enums.MembershipType],
1022    ) -> int:
1023        body = {
1024            "state": state,
1025            "itemId": item_id,
1026            "characterId": character_id,
1027            "membershipType": int(membership_type),
1028        }
1029        response = await self._request(
1030            RequestMethod.POST,
1031            "Destiny2/Actions/Items/SetLockState",
1032            json=body,
1033            auth=access_token,
1034        )
1035        assert isinstance(response, int)
1036        return response

Set the Lock State for an instanced item.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def set_quest_track_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: Union[int, MembershipType]) -> int:
1038    async def set_quest_track_state(
1039        self,
1040        access_token: str,
1041        state: bool,
1042        /,
1043        item_id: int,
1044        character_id: int,
1045        membership_type: typedefs.IntAnd[enums.MembershipType],
1046    ) -> int:
1047        body = {
1048            "state": state,
1049            "itemId": item_id,
1050            "characterId": character_id,
1051            "membership_type": int(membership_type),
1052        }
1053        response = await self._request(
1054            RequestMethod.POST,
1055            "Destiny2/Actions/Items/SetTrackedState",
1056            json=body,
1057            auth=access_token,
1058        )
1059        assert isinstance(response, int)
1060        return response

Set the Tracking State for an instanced Quest or Bounty.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def fetch_manifest_path(self) -> dict[str, typing.Any]:
1062    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1063        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1064        path = await self._request(RequestMethod.GET, "Destiny2/Manifest")
1065        assert isinstance(path, dict)
1066        return path

Fetch the manifest JSON paths.

Returns
  • typedefs.JSONObject: The manifest JSON paths.
async def read_manifest_bytes(self, language: str = 'en', /) -> bytes:
1068    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1069        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1070        _ensure_manifest_language(language)
1071
1072        content = await self.fetch_manifest_path()
1073        resp = await self._request(
1074            RequestMethod.GET,
1075            content["mobileWorldContentPaths"][language],
1076            unwrapping="read",
1077            base=True,
1078        )
1079        assert isinstance(resp, bytes)
1080        return resp

Read raw manifest SQLite database bytes response.

This method can be used to write the bytes to zipped file and then extract it to get the manifest content.

Parameters
  • language (str): The manifest database language bytes to get.
Returns
  • bytes: The bytes to read and write the manifest database.
async def download_manifest( self, language: str = 'en', name: str = 'manifest', path: Union[pathlib.Path, str] = '.', *, force: bool = False) -> None:
1082    async def download_manifest(
1083        self,
1084        language: str = "en",
1085        name: str = "manifest",
1086        path: typing.Union[pathlib.Path, str] = ".",
1087        *,
1088        force: bool = False,
1089    ) -> None:
1090        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1091        complete_path = _get_path(name, path, sql=True)
1092
1093        if complete_path.exists() and force:
1094            if force:
1095                _LOG.info(
1096                    f"Found manifest in {complete_path!s}. Forcing to Re-Download."
1097                )
1098                complete_path.unlink(missing_ok=True)
1099
1100                return await self.download_manifest(language, name, path, force=force)
1101
1102            else:
1103                raise FileExistsError(
1104                    "Manifest file already exists, "
1105                    "To force download, set the `force` parameter to `True`."
1106                )
1107
1108        _LOG.info(f"Downloading manifest. Location: {complete_path!s}")
1109        data_bytes = await self.read_manifest_bytes(language)
1110        await asyncio.get_running_loop().run_in_executor(
1111            None, _write_sqlite_bytes, data_bytes, path, name
1112        )

A helper method to download the manifest.

Note

This method downloads the sqlite database and not JSON. Use RESTInterface.download_json_manifest for the JSON version.

Parameters
  • language (str): The manifest language to download, Default is english.
  • path (str | pathlib.Path): The path to save the manifest sqlite database. Example "D:/", Default is the current directory.
  • name (str): The manifest database file name. Default is manifest
  • force (bool): Whether to force the download. Default is False. However if set to true the old file will get removed and a new one will being to download.
Returns
  • None
Raises
  • FileNotFoundError: If the manifest file exists and force is False.
  • ValueError: If the provided language was not recognized.
async def download_json_manifest( self, file_name: str = 'manifest', path: Union[str, pathlib.Path] = '.', language: str = 'en') -> None:
1114    async def download_json_manifest(
1115        self,
1116        file_name: str = "manifest",
1117        path: typing.Union[str, pathlib.Path] = ".",
1118        language: str = "en",
1119    ) -> None:
1120        _ensure_manifest_language(language)
1121
1122        _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...")
1123
1124        content = await self.fetch_manifest_path()
1125        json_bytes = await self._request(
1126            RequestMethod.GET,
1127            content["jsonWorldContentPaths"][language],
1128            unwrapping="read",
1129            base=True,
1130        )
1131
1132        await asyncio.get_running_loop().run_in_executor(
1133            None, _write_json_bytes, json_bytes, file_name, path
1134        )
1135        _LOG.info("Finished downloading manifest JSON.")

Download the Bungie manifest json file.

Parameters
  • file_name (str): The file name to save the manifest json file. Default is manifest.
  • path (str | pathlib.Path): The path to save the manifest json file. Default is the current directory. Example "D:/"
  • language (str): The manifest database language bytes to get. Default is English.
async def fetch_manifest_version(self) -> str:
1137    async def fetch_manifest_version(self) -> str:
1138        return typing.cast(str, (await self.fetch_manifest_path())["version"])

Fetch the manifest version.

Returns
  • str: The manifest version.
async def fetch_linked_profiles( self, member_id: int, member_type: Union[int, MembershipType], /, *, all: bool = False) -> dict[str, typing.Any]:
1140    async def fetch_linked_profiles(
1141        self,
1142        member_id: int,
1143        member_type: typedefs.IntAnd[enums.MembershipType],
1144        /,
1145        *,
1146        all: bool = False,
1147    ) -> typedefs.JSONObject:
1148        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1149        resp = await self._request(
1150            RequestMethod.GET,
1151            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1152        )
1153        assert isinstance(resp, dict)
1154        return resp

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether thry're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
async def fetch_clan_banners(self) -> dict[str, typing.Any]:
1156    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1157        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1158        resp = await self._request(
1159            RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/"
1160        )
1161        assert isinstance(resp, dict)
1162        return resp

Fetch the values of the clan banners.

Returns
async def fetch_public_milestones(self) -> dict[str, typing.Any]:
1164    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1165        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1166        resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/")
1167        assert isinstance(resp, dict)
1168        return resp

Fetch the available milestones.

Returns
async def fetch_public_milestone_content(self, milestone_hash: int, /) -> dict[str, typing.Any]:
1170    async def fetch_public_milestone_content(
1171        self, milestone_hash: int, /
1172    ) -> typedefs.JSONObject:
1173        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1174        resp = await self._request(
1175            RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1176        )
1177        assert isinstance(resp, dict)
1178        return resp

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
async def fetch_current_user_memberships(self, access_token: str, /) -> dict[str, typing.Any]:
1180    async def fetch_current_user_memberships(
1181        self, access_token: str, /
1182    ) -> typedefs.JSONObject:
1183        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1184        resp = await self._request(
1185            RequestMethod.GET,
1186            "User/GetMembershipsForCurrentUser/",
1187            auth=access_token,
1188        )
1189        assert isinstance(resp, dict)
1190        return resp

Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.

This requires OAuth2 scope enabled and the valid Bearer access_token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def equip_item( self, access_token: str, /, item_id: int, character_id: int, membership_type: Union[int, MembershipType]) -> None:
1192    async def equip_item(
1193        self,
1194        access_token: str,
1195        /,
1196        item_id: int,
1197        character_id: int,
1198        membership_type: typedefs.IntAnd[enums.MembershipType],
1199    ) -> None:
1200        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1201        payload = {
1202            "itemId": item_id,
1203            "characterId": character_id,
1204            "membershipType": int(membership_type),
1205        }
1206
1207        await self._request(
1208            RequestMethod.POST,
1209            "Destiny2/Actions/Items/EquipItem/",
1210            json=payload,
1211            auth=access_token,
1212        )

Equip an item to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item id.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
async def equip_items( self, access_token: str, /, item_ids: list[int], character_id: int, membership_type: Union[int, MembershipType]) -> None:
1214    async def equip_items(
1215        self,
1216        access_token: str,
1217        /,
1218        item_ids: list[int],
1219        character_id: int,
1220        membership_type: typedefs.IntAnd[enums.MembershipType],
1221    ) -> None:
1222        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1223        payload = {
1224            "itemIds": item_ids,
1225            "characterId": character_id,
1226            "membershipType": int(membership_type),
1227        }
1228        await self._request(
1229            RequestMethod.POST,
1230            "Destiny2/Actions/Items/EquipItems/",
1231            json=payload,
1232            auth=access_token,
1233        )

Equip multiple items to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_ids (list[int]): A list of item ids.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
async def ban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, MembershipType], *, length: int = 0, comment: Union[UndefinedType, str] = UNDEFINED) -> None:
1235    async def ban_clan_member(
1236        self,
1237        access_token: str,
1238        /,
1239        group_id: int,
1240        membership_id: int,
1241        membership_type: typedefs.IntAnd[enums.MembershipType],
1242        *,
1243        length: int = 0,
1244        comment: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1245    ) -> None:
1246        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1247        payload = {"comment": str(comment), "length": length}
1248        await self._request(
1249            RequestMethod.POST,
1250            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1251            json=payload,
1252            auth=access_token,
1253        )

Bans a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to ban.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
async def unban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, MembershipType]) -> None:
1255    async def unban_clan_member(
1256        self,
1257        access_token: str,
1258        /,
1259        group_id: int,
1260        membership_id: int,
1261        membership_type: typedefs.IntAnd[enums.MembershipType],
1262    ) -> None:
1263        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1264        await self._request(
1265            RequestMethod.POST,
1266            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1267            auth=access_token,
1268        )

Unbans a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to unban.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, MembershipType]) -> dict[str, typing.Any]:
1270    async def kick_clan_member(
1271        self,
1272        access_token: str,
1273        /,
1274        group_id: int,
1275        membership_id: int,
1276        membership_type: typedefs.IntAnd[enums.MembershipType],
1277    ) -> typedefs.JSONObject:
1278        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1279        resp = await self._request(
1280            RequestMethod.POST,
1281            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1282            auth=access_token,
1283        )
1284        assert isinstance(resp, dict)
1285        return resp

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
async def edit_clan( self, access_token: str, /, group_id: int, *, name: Optional[str] = None, about: Optional[str] = None, motto: Optional[str] = None, theme: Optional[str] = None, tags: Optional[collections.abc.Sequence[str]] = None, is_public: Optional[bool] = None, locale: Optional[str] = None, avatar_image_index: Optional[int] = None, membership_option: Union[NoneType, int, MembershipOption] = None, allow_chat: Optional[bool] = None, chat_security: Optional[Literal[0, 1]] = None, call_sign: Optional[str] = None, homepage: Optional[Literal[0, 1, 2]] = None, enable_invite_messaging_for_admins: Optional[bool] = None, default_publicity: Optional[Literal[0, 1, 2]] = None, is_public_topic_admin: Optional[bool] = None) -> None:
1287    async def edit_clan(
1288        self,
1289        access_token: str,
1290        /,
1291        group_id: int,
1292        *,
1293        name: typedefs.NoneOr[str] = None,
1294        about: typedefs.NoneOr[str] = None,
1295        motto: typedefs.NoneOr[str] = None,
1296        theme: typedefs.NoneOr[str] = None,
1297        tags: typedefs.NoneOr[collections.Sequence[str]] = None,
1298        is_public: typedefs.NoneOr[bool] = None,
1299        locale: typedefs.NoneOr[str] = None,
1300        avatar_image_index: typedefs.NoneOr[int] = None,
1301        membership_option: typedefs.NoneOr[
1302            typedefs.IntAnd[enums.MembershipOption]
1303        ] = None,
1304        allow_chat: typedefs.NoneOr[bool] = None,
1305        chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None,
1306        call_sign: typedefs.NoneOr[str] = None,
1307        homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1308        enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None,
1309        default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1310        is_public_topic_admin: typedefs.NoneOr[bool] = None,
1311    ) -> None:
1312        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1313        payload = {
1314            "name": name,
1315            "about": about,
1316            "motto": motto,
1317            "theme": theme,
1318            "tags": tags,
1319            "isPublic": is_public,
1320            "avatarImageIndex": avatar_image_index,
1321            "isPublicTopicAdminOnly": is_public_topic_admin,
1322            "allowChat": allow_chat,
1323            "chatSecurity": chat_security,
1324            "callsign": call_sign,
1325            "homepage": homepage,
1326            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1327            "defaultPublicity": default_publicity,
1328            "locale": locale,
1329        }
1330        if membership_option is not None:
1331            payload["membershipOption"] = int(membership_option)
1332
1333        await self._request(
1334            RequestMethod.POST,
1335            f"GroupV2/{group_id}/Edit",
1336            json=payload,
1337            auth=access_token,
1338        )

Edit a clan.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id to edit.
Other Parameters
async def edit_clan_options( self, access_token: str, /, group_id: int, *, invite_permissions_override: Optional[bool] = None, update_culture_permissionOverride: Optional[bool] = None, host_guided_game_permission_override: Optional[Literal[0, 1, 2]] = None, update_banner_permission_override: Optional[bool] = None, join_level: Union[NoneType, int, ClanMemberType] = None) -> None:
1340    async def edit_clan_options(
1341        self,
1342        access_token: str,
1343        /,
1344        group_id: int,
1345        *,
1346        invite_permissions_override: typedefs.NoneOr[bool] = None,
1347        update_culture_permissionOverride: typedefs.NoneOr[bool] = None,
1348        host_guided_game_permission_override: typedefs.NoneOr[
1349            typing.Literal[0, 1, 2]
1350        ] = None,
1351        update_banner_permission_override: typedefs.NoneOr[bool] = None,
1352        join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None,
1353    ) -> None:
1354        payload = {
1355            "InvitePermissionOverride": invite_permissions_override,
1356            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1357            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1358            "UpdateBannerPermissionOverride": update_banner_permission_override,
1359            "JoinLevel": int(join_level) if join_level else None,
1360        }
1361
1362        await self._request(
1363            RequestMethod.POST,
1364            f"GroupV2/{group_id}/EditFounderOptions",
1365            json=payload,
1366            auth=access_token,
1367        )

Edit the clan options.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
Other Parameters
  • invite_permissions_override (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • update_culture_permissionOverride (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • host_guided_game_permission_override (aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides: 0 -> None, 1 -> Beginner 2 -> Member. Default is Member for clans, None for groups, although this means nothing for groups.
  • update_banner_permission_override (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • join_level (aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default is aiobungie.ClanMemberType.BEGINNER
async def fetch_friends(self, access_token: str, /) -> dict[str, typing.Any]:
1369    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1370        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1371        resp = await self._request(
1372            RequestMethod.GET,
1373            "Social/Friends/",
1374            auth=access_token,
1375        )
1376        assert isinstance(resp, dict)
1377        return resp

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> dict[str, typing.Any]:
1379    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1380        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1381        resp = await self._request(
1382            RequestMethod.GET,
1383            "Social/Friends/Requests",
1384            auth=access_token,
1385        )
1386        assert isinstance(resp, dict)
1387        return resp

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1389    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1390        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1391        await self._request(
1392            RequestMethod.POST,
1393            f"Social/Friends/Requests/Accept/{member_id}",
1394            auth=access_token,
1395        )

Accepts a friend relationship with the target user. The user must be on your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to accept.
async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1397    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1398        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1399        await self._request(
1400            RequestMethod.POST,
1401            f"Social/Friends/Add/{member_id}",
1402            auth=access_token,
1403        )

Requests a friend relationship with the target user.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to send the request to.
async def decline_friend_request(self, access_token: str, /, member_id: int) -> None:
1405    async def decline_friend_request(
1406        self, access_token: str, /, member_id: int
1407    ) -> None:
1408        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1409        await self._request(
1410            RequestMethod.POST,
1411            f"Social/Friends/Requests/Decline/{member_id}",
1412            auth=access_token,
1413        )

Decline a friend request with the target user. The user must be in your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to decline.
async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1415    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1416        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1417        await self._request(
1418            RequestMethod.POST,
1419            f"Social/Friends/Remove/{member_id}",
1420            auth=access_token,
1421        )

Removes a friend from your friend list. The user must be in your friend list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove.
async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1423    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1424        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1425        await self._request(
1426            RequestMethod.POST,
1427            f"Social/Friends/Requests/Remove/{member_id}",
1428            auth=access_token,
1429        )

Removes a friend from your friend list requests. The user must be in your outgoing request list.

.. note : This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove from the requested friend list.
async def approve_all_pending_group_users( self, access_token: str, /, group_id: int, message: Union[UndefinedType, str] = UNDEFINED) -> None:
1431    async def approve_all_pending_group_users(
1432        self,
1433        access_token: str,
1434        /,
1435        group_id: int,
1436        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1437    ) -> None:
1438        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1439        await self._request(
1440            RequestMethod.POST,
1441            f"GroupV2/{group_id}/Members/ApproveAll",
1442            auth=access_token,
1443            json={"message": str(message)},
1444        )

Approve all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
async def deny_all_pending_group_users( self, access_token: str, /, group_id: int, *, message: Union[UndefinedType, str] = UNDEFINED) -> None:
1446    async def deny_all_pending_group_users(
1447        self,
1448        access_token: str,
1449        /,
1450        group_id: int,
1451        *,
1452        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1453    ) -> None:
1454        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1455        await self._request(
1456            RequestMethod.POST,
1457            f"GroupV2/{group_id}/Members/DenyAll",
1458            auth=access_token,
1459            json={"message": str(message)},
1460        )

Deny all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
async def add_optional_conversation( self, access_token: str, /, group_id: int, *, name: Union[UndefinedType, str] = UNDEFINED, security: Literal[0, 1] = 0) -> None:
1462    async def add_optional_conversation(
1463        self,
1464        access_token: str,
1465        /,
1466        group_id: int,
1467        *,
1468        name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1469        security: typing.Literal[0, 1] = 0,
1470    ) -> None:
1471        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1472        payload = {"chatName": str(name), "chatSecurity": security}
1473        await self._request(
1474            RequestMethod.POST,
1475            f"GroupV2/{group_id}/OptionalConversations/Add",
1476            json=payload,
1477            auth=access_token,
1478        )

Add a new chat channel to a group.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other parameters

name: aiobungie.UndefinedOr[str] The chat name. Default to UNDEFINED security: typing.Literal[0, 1] The security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
async def edit_optional_conversation( self, access_token: str, /, group_id: int, conversation_id: int, *, name: Union[UndefinedType, str] = UNDEFINED, security: Literal[0, 1] = 0, enable_chat: bool = False) -> None:
1480    async def edit_optional_conversation(
1481        self,
1482        access_token: str,
1483        /,
1484        group_id: int,
1485        conversation_id: int,
1486        *,
1487        name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1488        security: typing.Literal[0, 1] = 0,
1489        enable_chat: bool = False,
1490    ) -> None:
1491        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1492        payload = {
1493            "chatEnabled": enable_chat,
1494            "chatName": str(name),
1495            "chatSecurity": security,
1496        }
1497        await self._request(
1498            RequestMethod.POST,
1499            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1500            json=payload,
1501            auth=access_token,
1502        )

Edit the settings of this chat channel.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
  • conversation_id (int): The conversation/chat id.
Other parameters

name: aiobungie.UndefinedOr[str] The new chat name. Default to UNDEFINED security: typing.Literal[0, 1] The new security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`

enable_chat : bool Whether to enable chatting or not. If set to True then chatting will be enabled. Otherwise it will be disabled.

async def transfer_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: Union[int, MembershipType], *, stack_size: int = 1, vault: bool = False) -> None:
1504    async def transfer_item(
1505        self,
1506        access_token: str,
1507        /,
1508        item_id: int,
1509        item_hash: int,
1510        character_id: int,
1511        member_type: typedefs.IntAnd[enums.MembershipType],
1512        *,
1513        stack_size: int = 1,
1514        vault: bool = False,
1515    ) -> None:
1516        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1517        payload = {
1518            "characterId": character_id,
1519            "membershipType": int(member_type),
1520            "itemId": item_id,
1521            "itemReferenceHash": item_hash,
1522            "stackSize": stack_size,
1523            "transferToVault": vault,
1524        }
1525        await self._request(
1526            RequestMethod.POST,
1527            "Destiny2/Actions/Items/TransferItem",
1528            json=payload,
1529            auth=access_token,
1530        )

Transfer an item from / to your vault.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id you to transfer.
  • item_hash (int): The item hash.
  • character_id (int): The character id to transfer the item from/to.
  • member_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • valut (bool): Whether to transfer this item to your valut or not. Defaults to False.
async def pull_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: Union[int, MembershipType], *, stack_size: int = 1, vault: bool = False) -> None:
1532    async def pull_item(
1533        self,
1534        access_token: str,
1535        /,
1536        item_id: int,
1537        item_hash: int,
1538        character_id: int,
1539        member_type: typedefs.IntAnd[enums.MembershipType],
1540        *,
1541        stack_size: int = 1,
1542        vault: bool = False,
1543    ) -> None:
1544        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1545        payload = {
1546            "characterId": character_id,
1547            "membershipType": int(member_type),
1548            "itemId": item_id,
1549            "itemReferenceHash": item_hash,
1550            "stackSize": stack_size,
1551            "transferToVault": vault,
1552        }
1553        await self._request(
1554            RequestMethod.POST,
1555            "Destiny2/Actions/Items/PullFromPostmaster",
1556            json=payload,
1557            auth=access_token,
1558        )

pull an item from the postmaster.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id to pull.
  • item_hash (int): The item hash.
  • character_id (int): The character id to pull the item to.
  • member_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • valut (bool): Whether to pill this item to your valut or not. Defaults to False.
async def fetch_fireteams( self, activity_type: Union[int, FireteamActivity], *, platform: Union[int, FireteamPlatform] = <FireteamPlatform.ANY: 0>, language: Union[FireteamLanguage, str] = <FireteamLanguage.ALL: >, date_range: Union[int, FireteamDate] = <FireteamDate.ALL: 0>, page: int = 0, slots_filter: int = 0) -> dict[str, typing.Any]:
1560    async def fetch_fireteams(
1561        self,
1562        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1563        *,
1564        platform: typedefs.IntAnd[
1565            fireteams.FireteamPlatform
1566        ] = fireteams.FireteamPlatform.ANY,
1567        language: typing.Union[
1568            fireteams.FireteamLanguage, str
1569        ] = fireteams.FireteamLanguage.ALL,
1570        date_range: typedefs.IntAnd[
1571            fireteams.FireteamDate
1572        ] = fireteams.FireteamDate.ALL,
1573        page: int = 0,
1574        slots_filter: int = 0,
1575    ) -> typedefs.JSONObject:
1576        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1577        resp = await self._request(
1578            RequestMethod.GET,
1579            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1580        )
1581        assert isinstance(resp, dict)
1582        return resp

Fetch public Bungie fireteams with open slots.

Parameters
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_avaliable_clan_fireteams( self, access_token: str, group_id: int, activity_type: Union[int, FireteamActivity], *, platform: Union[int, FireteamPlatform], language: Union[FireteamLanguage, str], date_range: Union[int, FireteamDate] = <FireteamDate.ALL: 0>, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> dict[str, typing.Any]:
1584    async def fetch_avaliable_clan_fireteams(
1585        self,
1586        access_token: str,
1587        group_id: int,
1588        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1589        *,
1590        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1591        language: typing.Union[fireteams.FireteamLanguage, str],
1592        date_range: typedefs.IntAnd[
1593            fireteams.FireteamDate
1594        ] = fireteams.FireteamDate.ALL,
1595        page: int = 0,
1596        public_only: bool = False,
1597        slots_filter: int = 0,
1598    ) -> typedefs.JSONObject:
1599        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1600        resp = await self._request(
1601            RequestMethod.GET,
1602            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1603            json={"langFilter": str(language)},
1604            auth=access_token,
1605        )
1606        assert isinstance(resp, dict)
1607        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> dict[str, typing.Any]:
1609    async def fetch_clan_fireteam(
1610        self, access_token: str, fireteam_id: int, group_id: int
1611    ) -> typedefs.JSONObject:
1612        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1613        resp = await self._request(
1614            RequestMethod.GET,
1615            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1616            auth=access_token,
1617        )
1618        assert isinstance(resp, dict)
1619        return resp

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: Union[int, FireteamPlatform], language: Union[FireteamLanguage, str], filtered: bool = True, page: int = 0) -> dict[str, typing.Any]:
1621    async def fetch_my_clan_fireteams(
1622        self,
1623        access_token: str,
1624        group_id: int,
1625        *,
1626        include_closed: bool = True,
1627        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1628        language: typing.Union[fireteams.FireteamLanguage, str],
1629        filtered: bool = True,
1630        page: int = 0,
1631    ) -> typedefs.JSONObject:
1632        payload = {"groupFilter": filtered, "langFilter": str(language)}
1633        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1634        resp = await self._request(
1635            RequestMethod.GET,
1636            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1637            json=payload,
1638            auth=access_token,
1639        )
1640        assert isinstance(resp, dict)
1641        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.typedefs.IntAnd[FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_private_clan_fireteams(self, access_token: str, group_id: int, /) -> int:
1643    async def fetch_private_clan_fireteams(
1644        self, access_token: str, group_id: int, /
1645    ) -> int:
1646        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1647        resp = await self._request(
1648            RequestMethod.GET,
1649            f"Fireteam/Clan/{group_id}/ActiveCount",
1650            auth=access_token,
1651        )
1652        assert isinstance(resp, int)
1653        return resp

Fetch the active count of the clan fireteams that are only private.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id.
Returns
  • int: The active fireteams count. Max value returned is 25.
async def fetch_post_activity(self, instance_id: int, /) -> dict[str, typing.Any]:
1655    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1656        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1657        resp = await self._request(
1658            RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1659        )
1660        assert isinstance(resp, dict)
1661        return resp

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> dict[str, typing.Any]:
1663    async def search_entities(
1664        self, name: str, entity_type: str, *, page: int = 0
1665    ) -> typedefs.JSONObject:
1666        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1667        resp = await self._request(
1668            RequestMethod.GET,
1669            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1670            json={"page": page},
1671        )
1672        assert isinstance(resp, dict)
1673        return resp

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: Union[int, MembershipType]) -> dict[str, typing.Any]:
1675    async def fetch_unique_weapon_history(
1676        self,
1677        membership_id: int,
1678        character_id: int,
1679        membership_type: typedefs.IntAnd[enums.MembershipType],
1680    ) -> typedefs.JSONObject:
1681        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1682        resp = await self._request(
1683            RequestMethod.GET,
1684            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1685        )
1686        assert isinstance(resp, dict)
1687        return resp

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
Returns
async def fetch_item( self, member_id: int, item_id: int, membership_type: Union[int, MembershipType], components: list[ComponentType]) -> dict[str, typing.Any]:
1689    async def fetch_item(
1690        self,
1691        member_id: int,
1692        item_id: int,
1693        membership_type: typedefs.IntAnd[enums.MembershipType],
1694        components: list[enums.ComponentType],
1695    ) -> typedefs.JSONObject:
1696        collector = _collect_components(components)
1697        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1698        resp = await self._request(
1699            RequestMethod.GET,
1700            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1701        )
1702        assert isinstance(resp, dict)
1703        return resp

Fetch an instanced Destiny 2 item's details.

Parameters
Returns
async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> dict[str, typing.Any]:
1705    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1706        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1707        resp = await self._request(
1708            RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/"
1709        )
1710        assert isinstance(resp, dict)
1711        return resp

Fetch the weekly reward state for a clan.

Parameters
  • clan_id (int): The clan id.
Returns
async def fetch_available_locales(self) -> dict[str, typing.Any]:
1713    async def fetch_available_locales(self) -> typedefs.JSONObject:
1714        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1715        resp = await self._request(
1716            RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/"
1717        )
1718        assert isinstance(resp, dict)
1719        return resp

Fetch available locales at Bungie.

Returns
async def fetch_common_settings(self) -> dict[str, typing.Any]:
1721    async def fetch_common_settings(self) -> typedefs.JSONObject:
1722        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1723        resp = await self._request(RequestMethod.GET, "Settings")
1724        assert isinstance(resp, dict)
1725        return resp

Fetch the common settings used by Bungie's envirotment.

Returns
async def fetch_user_systems_overrides(self) -> dict[str, typing.Any]:
1727    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1728        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1729        resp = await self._request(RequestMethod.GET, "UserSystemOverrides")
1730        assert isinstance(resp, dict)
1731        return resp

Fetch a user's specific system overrides.

Returns
async def fetch_global_alerts(self, *, include_streaming: bool = False) -> list[typing.Any]:
1733    async def fetch_global_alerts(
1734        self, *, include_streaming: bool = False
1735    ) -> typedefs.JSONArray:
1736        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1737        resp = await self._request(
1738            RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1739        )
1740        assert isinstance(resp, list)
1741        return resp

Fetch any active global alerts.

Parameters
  • include_streaming (bool): If True, the returned results will include streaming alerts. Default is False.
Returns
async def awainitialize_request( self, access_token: str, type: Literal[0, 1], membership_type: Union[int, MembershipType], /, *, affected_item_id: Optional[int] = None, character_id: Optional[int] = None) -> dict[str, typing.Any]:
1743    async def awainitialize_request(
1744        self,
1745        access_token: str,
1746        type: typing.Literal[0, 1],
1747        membership_type: typedefs.IntAnd[enums.MembershipType],
1748        /,
1749        *,
1750        affected_item_id: typing.Optional[int] = None,
1751        character_id: typing.Optional[int] = None,
1752    ) -> typedefs.JSONObject:
1753        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1754
1755        body = {"type": type, "membershipType": int(membership_type)}
1756
1757        if affected_item_id is not None:
1758            body["affectedItemId"] = affected_item_id
1759
1760        if character_id is not None:
1761            body["characterId"] = character_id
1762
1763        resp = await self._request(
1764            RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1765        )
1766        assert isinstance(resp, dict)
1767        return resp

Initialize a request to perform an advanced write action.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • type (typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means it None. Otherwise if 1 that means its insert plugs.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type of the account to modify.
Other Parameters
  • affected_item_id (typing.Optional[int]): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values.
  • character_id (typing.Optional[int]): The Destiny character ID to perform this action on.
Returns
async def awaget_action_token(self, access_token: str, correlation_id: str, /) -> dict[str, typing.Any]:
1769    async def awaget_action_token(
1770        self, access_token: str, correlation_id: str, /
1771    ) -> typedefs.JSONObject:
1772        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1773        resp = await self._request(
1774            RequestMethod.POST,
1775            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1776            auth=access_token,
1777        )
1778        assert isinstance(resp, dict)
1779        return resp

Returns the action token if user approves the request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • correlation_id (str): The identifier for the advanced write action request.
Returns
async def awa_provide_authorization_result( self, access_token: str, selection: int, correlation_id: str, nonce: collections.abc.MutableSequence[typing.Union[str, bytes]]) -> int:
1781    async def awa_provide_authorization_result(
1782        self,
1783        access_token: str,
1784        selection: int,
1785        correlation_id: str,
1786        nonce: collections.MutableSequence[typing.Union[str, bytes]],
1787    ) -> int:
1788        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1789
1790        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1791
1792        resp = await self._request(
1793            RequestMethod.POST,
1794            "Destiny2/Awa/AwaProvideAuthorizationResult",
1795            json=body,
1796            auth=access_token,
1797        )
1798        assert isinstance(resp, int)
1799        return resp

Provide the result of the user interaction. Called by the Bungie Destiny App to approve or reject a request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • selection (int): Indication of the selection the user has made (Approving or rejecting the action)
  • correlation_id (str): Correlation ID of the request.
  • nonce (collections.MutableSequence[str, bytes]): Secret nonce received via the PUSH notification.
Returns
  • int: ...
async def fetch_vendors( self, access_token: str, character_id: int, membership_id: int, membership_type: Union[int, MembershipType], /, components: list[ComponentType], filter: Optional[int] = None) -> dict[str, typing.Any]:
1801    async def fetch_vendors(
1802        self,
1803        access_token: str,
1804        character_id: int,
1805        membership_id: int,
1806        membership_type: typedefs.IntAnd[enums.MembershipType],
1807        /,
1808        components: list[enums.ComponentType],
1809        filter: typing.Optional[int] = None,
1810    ) -> typedefs.JSONObject:
1811        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1812        components_ = _collect_components(components)
1813        route = (
1814            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1815            f"/Character/{character_id}/Vendors/?components={components_}"
1816        )
1817
1818        if filter is not None:
1819            route = route + f"&filter={filter}"
1820
1821        resp = await self._request(
1822            RequestMethod.GET,
1823            route,
1824            auth=access_token,
1825        )
1826        assert isinstance(resp, dict)
1827        return resp

Get currently available vendors from the list of vendors that can possibly have rotating inventory.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for.
  • components (list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
  • filter (int): Filters the type of items returned from the vendor. This can be left to None.
Returns
async def fetch_vendor( self, access_token: str, character_id: int, membership_id: int, membership_type: Union[int, MembershipType], vendor_hash: int, /, components: list[ComponentType]) -> dict[str, typing.Any]:
1829    async def fetch_vendor(
1830        self,
1831        access_token: str,
1832        character_id: int,
1833        membership_id: int,
1834        membership_type: typedefs.IntAnd[enums.MembershipType],
1835        vendor_hash: int,
1836        /,
1837        components: list[enums.ComponentType],
1838    ) -> typedefs.JSONObject:
1839        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1840        components_ = _collect_components(components)
1841        resp = await self._request(
1842            RequestMethod.GET,
1843            (
1844                f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1845                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1846            ),
1847            auth=access_token,
1848        )
1849        assert isinstance(resp, dict)
1850        return resp

Fetch details for a specific vendor.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for.
  • vendor_hash (int): The vendor hash to return the details for.
  • components (list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
async def fetch_application_api_usage( self, access_token: str, application_id: int, /, *, start: Optional[datetime.datetime] = None, end: Optional[datetime.datetime] = None) -> dict[str, typing.Any]:
1852    async def fetch_application_api_usage(
1853        self,
1854        access_token: str,
1855        application_id: int,
1856        /,
1857        *,
1858        start: typing.Optional[datetime.datetime] = None,
1859        end: typing.Optional[datetime.datetime] = None,
1860    ) -> typedefs.JSONObject:
1861        end_date, start_date = time.parse_date_range(end, start)
1862        resp = await self._request(
1863            RequestMethod.GET,
1864            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1865            auth=access_token,
1866        )
1867        assert isinstance(resp, dict)
1868        return resp

Fetch a Bungie application's API usage.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • application_id (int): The application id to get.
Other Parameters
  • start (typing.Optional[datetime.datetime]): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.

    If this is left to None. It will return the last 24 hours.

  • end (typing.Optional[datetime.datetime]): A datetime object can be used to collect the end of the application usage.

    If this is left to None. It will return now.

Example
import datetime

# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
    start=datetime.datetime(2021, 12, 10), end=datetime.datetime(2021, 12, 20)
)
Returns
async def fetch_bungie_applications(self) -> list[typing.Any]:
1870    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1871        resp = await self._request(RequestMethod.GET, "App/FirstParty")
1872        assert isinstance(resp, list)
1873        return resp

Fetch details for applications created by Bungie.

Returns
async def fetch_content_type(self, type: str, /) -> dict[str, typing.Any]:
1875    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1876        resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/")
1877        assert isinstance(resp, dict)
1878        return resp
async def fetch_content_by_id( self, id: int, locale: str, /, *, head: bool = False) -> dict[str, typing.Any]:
1880    async def fetch_content_by_id(
1881        self, id: int, locale: str, /, *, head: bool = False
1882    ) -> typedefs.JSONObject:
1883        resp = await self._request(
1884            RequestMethod.GET,
1885            f"Content/GetContentById/{id}/{locale}/",
1886            json={"head": head},
1887        )
1888        assert isinstance(resp, dict)
1889        return resp
async def fetch_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, head: bool = False) -> dict[str, typing.Any]:
1891    async def fetch_content_by_tag_and_type(
1892        self, locale: str, tag: str, type: str, *, head: bool = False
1893    ) -> typedefs.JSONObject:
1894        resp = await self._request(
1895            RequestMethod.GET,
1896            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1897            json={"head": head},
1898        )
1899        assert isinstance(resp, dict)
1900        return resp
async def search_content_with_text( self, locale: str, /, content_type: str, search_text: str, tag: str, *, page: Union[UndefinedType, int] = UNDEFINED, source: Union[UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
1902    async def search_content_with_text(
1903        self,
1904        locale: str,
1905        /,
1906        content_type: str,
1907        search_text: str,
1908        tag: str,
1909        *,
1910        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1911        source: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1912    ) -> typedefs.JSONObject:
1913        body: typedefs.JSONObject = {}
1914
1915        body["ctype"] = content_type
1916        body["searchtext"] = search_text
1917        body["tag"] = tag
1918
1919        if page is not undefined.UNDEFINED:
1920            body["currentpage"] = page
1921        else:
1922            body["currentpage"] = 1
1923
1924        if source is not undefined.UNDEFINED:
1925            body["source"] = source
1926        else:
1927            source = ""
1928        resp = await self._request(
1929            RequestMethod.GET, f"Content/Search/{locale}/", json=body
1930        )
1931        assert isinstance(resp, dict)
1932        return resp
async def search_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, page: Union[UndefinedType, int] = UNDEFINED) -> dict[str, typing.Any]:
1934    async def search_content_by_tag_and_type(
1935        self,
1936        locale: str,
1937        tag: str,
1938        type: str,
1939        *,
1940        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1941    ) -> typedefs.JSONObject:
1942        body: typedefs.JSONObject = {}
1943        body["currentpage"] = 1 if page is undefined.UNDEFINED else page
1944        resp = await self._request(
1945            RequestMethod.GET,
1946            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
1947            json=body,
1948        )
1949        assert isinstance(resp, dict)
1950        return resp
async def search_help_articles(self, text: str, size: str, /) -> dict[str, typing.Any]:
1952    async def search_help_articles(
1953        self, text: str, size: str, /
1954    ) -> typedefs.JSONObject:
1955        resp = await self._request(
1956            RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/"
1957        )
1958        assert isinstance(resp, dict)
1959        return resp
async def fetch_topics_page( self, category_filter: int, group: int, date_filter: int, sort: Union[str, bytes], *, page: Union[UndefinedType, int] = UNDEFINED, locales: Union[UndefinedType, collections.abc.Iterable[str]] = UNDEFINED, tag_filter: Union[UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
1961    async def fetch_topics_page(
1962        self,
1963        category_filter: int,
1964        group: int,
1965        date_filter: int,
1966        sort: typing.Union[str, bytes],
1967        *,
1968        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1969        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED,
1970        tag_filter: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1971    ) -> typedefs.JSONObject:
1972        body: typedefs.JSONObject = {}
1973        if locales is not undefined.UNDEFINED:
1974            body["locales"] = ",".join(str(locales))
1975        else:
1976            body["locales"] = ",".join([])
1977
1978        if tag_filter is not undefined.UNDEFINED:
1979            body["tagstring"] = tag_filter
1980        else:
1981            body["tagstring"] = ""
1982
1983        page = 0 if page is not undefined.UNDEFINED else page
1984
1985        resp = await self._request(
1986            RequestMethod.GET,
1987            f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/",
1988            json=body,
1989        )
1990        assert isinstance(resp, dict)
1991        return resp
async def fetch_core_topics_page( self, category_filter: int, date_filter: int, sort: Union[str, bytes], *, page: Union[UndefinedType, int] = UNDEFINED, locales: Union[UndefinedType, collections.abc.Iterable[str]] = UNDEFINED) -> dict[str, typing.Any]:
1993    async def fetch_core_topics_page(
1994        self,
1995        category_filter: int,
1996        date_filter: int,
1997        sort: typing.Union[str, bytes],
1998        *,
1999        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
2000        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED,
2001    ) -> typedefs.JSONObject:
2002        body: typedefs.JSONObject = {}
2003
2004        if locales is not undefined.UNDEFINED:
2005            body["locales"] = ",".join(str(locales))
2006        else:
2007            body["locales"] = ",".join([])
2008
2009        resp = await self._request(
2010            RequestMethod.GET,
2011            f"Forum/GetCoreTopicsPaged/{0 if page is undefined.UNDEFINED else page}"
2012            f"/{sort!s}/{date_filter}/{category_filter}/",
2013            json=body,
2014        )
2015        assert isinstance(resp, dict)
2016        return resp
async def fetch_posts_threaded_page( self, parent_post: bool, page: int, page_size: int, parent_post_id: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2018    async def fetch_posts_threaded_page(
2019        self,
2020        parent_post: bool,
2021        page: int,
2022        page_size: int,
2023        parent_post_id: int,
2024        reply_size: int,
2025        root_thread_mode: bool,
2026        sort_mode: int,
2027        show_banned: typing.Optional[str] = None,
2028    ) -> typedefs.JSONObject:
2029        resp = await self._request(
2030            RequestMethod.GET,
2031            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
2032            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
2033            json={"showbanned": show_banned},
2034        )
2035        assert isinstance(resp, dict)
2036        return resp
async def fetch_posts_threaded_page_from_child( self, child_id: bool, page: int, page_size: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2038    async def fetch_posts_threaded_page_from_child(
2039        self,
2040        child_id: bool,
2041        page: int,
2042        page_size: int,
2043        reply_size: int,
2044        root_thread_mode: bool,
2045        sort_mode: int,
2046        show_banned: typing.Optional[str] = None,
2047    ) -> typedefs.JSONObject:
2048        resp = await self._request(
2049            RequestMethod.GET,
2050            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
2051            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
2052            json={"showbanned": show_banned},
2053        )
2054        assert isinstance(resp, dict)
2055        return resp
async def fetch_post_and_parent( self, child_id: int, /, *, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2057    async def fetch_post_and_parent(
2058        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2059    ) -> typedefs.JSONObject:
2060        resp = await self._request(
2061            RequestMethod.GET,
2062            f"Forum/GetPostAndParent/{child_id}/",
2063            json={"showbanned": show_banned},
2064        )
2065        assert isinstance(resp, dict)
2066        return resp
async def fetch_posts_and_parent_awaiting( self, child_id: int, /, *, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2068    async def fetch_posts_and_parent_awaiting(
2069        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2070    ) -> typedefs.JSONObject:
2071        resp = await self._request(
2072            RequestMethod.GET,
2073            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2074            json={"showbanned": show_banned},
2075        )
2076        assert isinstance(resp, dict)
2077        return resp
async def fetch_topic_for_content(self, content_id: int, /) -> int:
2079    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2080        resp = await self._request(
2081            RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/"
2082        )
2083        assert isinstance(resp, int)
2084        return resp
async def fetch_forum_tag_suggestions(self, partial_tag: str, /) -> dict[str, typing.Any]:
2086    async def fetch_forum_tag_suggestions(
2087        self, partial_tag: str, /
2088    ) -> typedefs.JSONObject:
2089        resp = await self._request(
2090            RequestMethod.GET,
2091            "Forum/GetForumTagSuggestions/",
2092            json={"partialtag": partial_tag},
2093        )
2094        assert isinstance(resp, dict)
2095        return resp
async def fetch_poll(self, topic_id: int, /) -> dict[str, typing.Any]:
2097    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2098        resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/")
2099        assert isinstance(resp, dict)
2100        return resp
async def fetch_recuirement_thread_summaries(self) -> list[typing.Any]:
2102    async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray:
2103        resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/")
2104        assert isinstance(resp, list)
2105        return resp
async def fetch_available_avatars(self) -> collections.abc.Mapping[str, int]:
2123    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2124        resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/")
2125        assert isinstance(resp, dict)
2126        return resp
async def fetch_user_clan_invite_setting( self, access_token: str, /, membership_type: Union[int, MembershipType]) -> bool:
2128    async def fetch_user_clan_invite_setting(
2129        self,
2130        access_token: str,
2131        /,
2132        membership_type: typedefs.IntAnd[enums.MembershipType],
2133    ) -> bool:
2134        resp = await self._request(
2135            RequestMethod.GET,
2136            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2137            auth=access_token,
2138        )
2139        assert isinstance(resp, bool)
2140        return resp
async def fetch_banned_group_members( self, access_token: str, group_id: int, /, *, page: int = 1) -> dict[str, typing.Any]:
2142    async def fetch_banned_group_members(
2143        self, access_token: str, group_id: int, /, *, page: int = 1
2144    ) -> typedefs.JSONObject:
2145        resp = await self._request(
2146            RequestMethod.GET,
2147            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2148            auth=access_token,
2149        )
2150        assert isinstance(resp, dict)
2151        return resp
async def fetch_pending_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> dict[str, typing.Any]:
2153    async def fetch_pending_group_memberships(
2154        self, access_token: str, group_id: int, /, *, current_page: int = 1
2155    ) -> typedefs.JSONObject:
2156        resp = await self._request(
2157            RequestMethod.GET,
2158            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2159            auth=access_token,
2160        )
2161        assert isinstance(resp, dict)
2162        return resp
async def fetch_invited_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> dict[str, typing.Any]:
2164    async def fetch_invited_group_memberships(
2165        self, access_token: str, group_id: int, /, *, current_page: int = 1
2166    ) -> typedefs.JSONObject:
2167        resp = await self._request(
2168            RequestMethod.GET,
2169            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2170            auth=access_token,
2171        )
2172        assert isinstance(resp, dict)
2173        return resp
async def invite_member_to_group( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, MembershipType], *, message: Union[UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
2175    async def invite_member_to_group(
2176        self,
2177        access_token: str,
2178        /,
2179        group_id: int,
2180        membership_id: int,
2181        membership_type: typedefs.IntAnd[enums.MembershipType],
2182        *,
2183        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
2184    ) -> typedefs.JSONObject:
2185        resp = await self._request(
2186            RequestMethod.POST,
2187            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2188            auth=access_token,
2189            json={"message": str(message)},
2190        )
2191        assert isinstance(resp, dict)
2192        return resp
async def cancel_group_member_invite( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, MembershipType]) -> dict[str, typing.Any]:
2194    async def cancel_group_member_invite(
2195        self,
2196        access_token: str,
2197        /,
2198        group_id: int,
2199        membership_id: int,
2200        membership_type: typedefs.IntAnd[enums.MembershipType],
2201    ) -> typedefs.JSONObject:
2202        resp = await self._request(
2203            RequestMethod.POST,
2204            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2205            auth=access_token,
2206        )
2207        assert isinstance(resp, dict)
2208        return resp
async def fetch_historical_definition(self) -> dict[str, typing.Any]:
2210    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2211        resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/")
2212        assert isinstance(resp, dict)
2213        return resp
async def fetch_historical_stats( self, character_id: int, membership_id: int, membership_type: Union[int, MembershipType], day_start: datetime.datetime, day_end: datetime.datetime, groups: list[typing.Union[int, aiobungie.internal.enums.StatsGroupType]], modes: collections.abc.Sequence[typing.Union[int, GameMode]], *, period_type: aiobungie.internal.enums.PeriodType = <PeriodType.ALL_TIME: 2>) -> dict[str, typing.Any]:
2215    async def fetch_historical_stats(
2216        self,
2217        character_id: int,
2218        membership_id: int,
2219        membership_type: typedefs.IntAnd[enums.MembershipType],
2220        day_start: datetime.datetime,
2221        day_end: datetime.datetime,
2222        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2223        modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]],
2224        *,
2225        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2226    ) -> typedefs.JSONObject:
2227        end, start = time.parse_date_range(day_end, day_start)
2228        resp = await self._request(
2229            RequestMethod.GET,
2230            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2231            json={
2232                "dayend": end,
2233                "daystart": start,
2234                "groups": [str(int(group)) for group in groups],
2235                "modes": [str(int(mode)) for mode in modes],
2236                "periodType": int(period_type),
2237            },
2238        )
2239        assert isinstance(resp, dict)
2240        return resp

Fetch historical stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • day_start (datetime.datetime): The start of the day to return the stats for.
  • day_end (datetime.datetime): The end of the day to return the stats for.
  • groups (list[aiobungie.StatsGroupType]): A list of stats groups to return.
  • modes (list[aiobungie.GameMode | int]): A list of game modes to return.
  • period_type (aiobungie.enums.PeriodType): The period type to return the stats for. This will return ALL_TIME by default if not modified.
Returns
async def fetch_historical_stats_for_account( self, membership_id: int, membership_type: Union[int, MembershipType], groups: list[typing.Union[int, aiobungie.internal.enums.StatsGroupType]]) -> dict[str, typing.Any]:
2242    async def fetch_historical_stats_for_account(
2243        self,
2244        membership_id: int,
2245        membership_type: typedefs.IntAnd[enums.MembershipType],
2246        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2247    ) -> typedefs.JSONObject:
2248        resp = await self._request(
2249            RequestMethod.GET,
2250            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2251            json={"groups": [str(int(group)) for group in groups]},
2252        )
2253        assert isinstance(resp, dict)
2254        return resp

Fetch historical stats for an account's membership.

Parameters
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • groups (list[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: Union[int, MembershipType], /) -> dict[str, typing.Any]:
2256    async def fetch_aggregated_activity_stats(
2257        self,
2258        character_id: int,
2259        membership_id: int,
2260        membership_type: typedefs.IntAnd[enums.MembershipType],
2261        /,
2262    ) -> typedefs.JSONObject:
2263        resp = await self._request(
2264            RequestMethod.GET,
2265            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2266            f"Character/{character_id}/Stats/AggregateActivityStats/",
2267        )
2268        assert isinstance(resp, dict)
2269        return resp

Fetch aggregated activity stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
async def equip_loadout( self, access_token: str, /, loadout_index: int, character_id: int, membership_type: Union[int, MembershipType]) -> None:
2271    async def equip_loadout(
2272        self,
2273        access_token: str,
2274        /,
2275        loadout_index: int,
2276        character_id: int,
2277        membership_type: typedefs.IntAnd[enums.MembershipType],
2278    ) -> None:
2279        response = await self._request(
2280            RequestMethod.POST,
2281            "Destiny2/Actions/Loadouts/EquipLoadout/",
2282            json={
2283                "loadoutIndex": loadout_index,
2284                "characterId": character_id,
2285                "membership_type": int(membership_type),
2286            },
2287            auth=access_token,
2288        )
2289        assert isinstance(response, int)

Equip a loadout. Youe character must be in a Social space, Orbit or Offline while performing this operation.

This operation requires MoveEquipDestinyItems OAuth2 scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • loadout_index (int): The index of the loadout to use.
  • character_id (int): The character ID to equip the loadout to.
  • membership_type (aiobungie.MembershipType | int): The membership type of the account.
async def snapshot_loadout( self, access_token: str, /, loadout_index: int, character_id: int, membership_type: Union[int, MembershipType], *, color_hash: Optional[int] = None, icon_hash: Optional[int] = None, name_hash: Optional[int] = None) -> None:
2291    async def snapshot_loadout(
2292        self,
2293        access_token: str,
2294        /,
2295        loadout_index: int,
2296        character_id: int,
2297        membership_type: typedefs.IntAnd[enums.MembershipType],
2298        *,
2299        color_hash: typing.Optional[int] = None,
2300        icon_hash: typing.Optional[int] = None,
2301        name_hash: typing.Optional[int] = None,
2302    ) -> None:
2303        response = await self._request(
2304            RequestMethod.POST,
2305            "Destiny2/Actions/Loadouts/SnapshotLoadout/",
2306            auth=access_token,
2307            json={
2308                "colorHash": color_hash,
2309                "iconHash": icon_hash,
2310                "nameHash": name_hash,
2311                "loadoutIndex": loadout_index,
2312                "characterId": character_id,
2313                "membershipType": int(membership_type),
2314            },
2315        )
2316        assert isinstance(response, int)

Snapshot a loadout with the currently equipped items.

This operation requires MoveEquipDestinyItems OAuth2 scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • loadout_index (int): The index of the loadout to use.
  • character_id (int): The character ID to equip the loadout to.
  • membership_type (aiobungie.MembershipType | int): The membership type of the account.
Other Parameters
  • color_hash (int | None): ...
  • icon_hash (int | None): ...
  • name_hash (int | None): ...
async def update_loadout( self, access_token: str, /, loadout_index: int, character_id: int, membership_type: Union[int, MembershipType], *, color_hash: Optional[int] = None, icon_hash: Optional[int] = None, name_hash: Optional[int] = None) -> None:
2318    async def update_loadout(
2319        self,
2320        access_token: str,
2321        /,
2322        loadout_index: int,
2323        character_id: int,
2324        membership_type: typedefs.IntAnd[enums.MembershipType],
2325        *,
2326        color_hash: typing.Optional[int] = None,
2327        icon_hash: typing.Optional[int] = None,
2328        name_hash: typing.Optional[int] = None,
2329    ) -> None:
2330        response = await self._request(
2331            RequestMethod.POST,
2332            "Destiny2/Actions/Loadouts/UpdateLoadoutIdentifiers/",
2333            auth=access_token,
2334            json={
2335                "colorHash": color_hash,
2336                "iconHash": icon_hash,
2337                "nameHash": name_hash,
2338                "loadoutIndex": loadout_index,
2339                "characterId": character_id,
2340                "membershipType": int(membership_type),
2341            },
2342        )
2343        assert isinstance(response, int)

Update the loadout. Color, Icon and Name.

This operation requires MoveEquipDestinyItems OAuth2 scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • loadout_index (int): The index of the loadout to use.
  • character_id (int): The character ID to equip the loadout to.
  • membership_type (aiobungie.MembershipType | int): The membership type of the account.
Other Parameters
  • color_hash (int | None): The new color hash of the loadout to update.
  • icon_hash (int | None): The new icon hash of the loadout to update.
  • name_hash (int | None): The new name hash of the loadout to update.
async def clear_loadout( self, access_token: str, /, loadout_index: int, character_id: int, membership_type: Union[int, MembershipType]) -> None:
2345    async def clear_loadout(
2346        self,
2347        access_token: str,
2348        /,
2349        loadout_index: int,
2350        character_id: int,
2351        membership_type: typedefs.IntAnd[enums.MembershipType],
2352    ) -> None:
2353        response = await self._request(
2354            RequestMethod.POST,
2355            "Destiny2/Actions/Loadouts/ClearLoadout/",
2356            json={
2357                "loadoutIndex": loadout_index,
2358                "characterId": character_id,
2359                "membership_type": int(membership_type),
2360            },
2361            auth=access_token,
2362        )
2363        assert isinstance(response, int)

Clear the identifiers and items of a loadout.

This operation requires MoveEquipDestinyItems OAuth2 scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • loadout_index (int): The index of the loadout to use.
  • character_id (int): The character ID to equip the loadout to.
  • membership_type (aiobungie.MembershipType | int): The membership type of the account.
class RESTPool:
196class RESTPool:
197    """Pool of `RESTClient` instances.
198
199    This allows to create multiple instances of `RESTClient`s that can be acquired
200    which share the same config and metadata.
201
202    Example
203    -------
204    ```py
205    import aiobungie
206    import asyncio
207
208    client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')
209
210    # Using a context manager to acquire an instance
211    # of the pool and close the connection after finishing.
212
213    async def first() -> str:
214        async with client_pool.acquire() as client:
215            return client.build_oauth2_url()
216
217    async def second() -> None:
218        async with client_pool.acquire() as client:
219            new_tokens = await client.refresh_access_token("token")
220            client.metadata['tokens'] = new_tokens
221
222    # Client instances are independent from first and second.
223    await asyncio.gather(first(), second())
224    ```
225
226    Parameters
227    ----------
228    token : `str`
229        A valid application token from Bungie's developer portal.
230
231    Other Parameters
232    ----------------
233    max_retries : `int`
234        The max retries number to retry if the request hit a `5xx` status code.
235    client_secret : `typing.Optional[str]`
236        An optional application client secret,
237        This is only needed if you're fetching OAuth2 tokens with this client.
238    client_id : `typing.Optional[int]`
239        An optional application client id,
240        This is only needed if you're fetching OAuth2 tokens with this client.
241    enable_debugging : `bool | str`
242        Whether to enable logging responses or not.
243
244    Logging Levels
245    --------------
246    * `False`: This will disable logging.
247    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
248    Like the response status, route, taken time and so on.
249    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
250    """
251
252    __slots__ = (
253        "_token",
254        "_max_retries",
255        "_client_secret",
256        "_client_id",
257        "_metadata",
258        "_enable_debug",
259        "_client_session",
260    )
261
262    # Looks like mypy doesn't like this.
263    if typing.TYPE_CHECKING:
264        _enable_debug: typing.Union[typing.Literal["TRACE"], bool, int]
265
266    def __init__(
267        self,
268        token: str,
269        /,
270        *,
271        client_secret: typing.Optional[str] = None,
272        client_id: typing.Optional[int] = None,
273        client_session: typing.Optional[aiohttp.ClientSession] = None,
274        max_retries: int = 4,
275        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
276    ) -> None:
277        self._client_secret = client_secret
278        self._client_id = client_id
279        self._token: str = token
280        self._max_retries = max_retries
281        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
282        self._enable_debug = enable_debugging
283        self._client_session = client_session
284
285    @property
286    def client_id(self) -> typing.Optional[int]:
287        return self._client_id
288
289    @property
290    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
291        """Pool's Metadata. This is different from client instance metadata."""
292        return self._metadata
293
294    @typing.final
295    def acquire(self) -> RESTClient:
296        """Acquires a new `RESTClient` instance from this REST pool.
297
298        Returns
299        -------
300        `RESTClient`
301            An instance of a REST client.
302        """
303        return RESTClient(
304            self._token,
305            client_secret=self._client_secret,
306            client_id=self._client_id,
307            max_retries=self._max_retries,
308            enable_debugging=self._enable_debug,
309            client_session=self._client_session,
310        )

Pool of RESTClient instances.

This allows to create multiple instances of RESTClients that can be acquired which share the same config and metadata.

Example
import aiobungie
import asyncio

client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')

# Using a context manager to acquire an instance
# of the pool and close the connection after finishing.

async def first() -> str:
    async with client_pool.acquire() as client:
        return client.build_oauth2_url()

async def second() -> None:
    async with client_pool.acquire() as client:
        new_tokens = await client.refresh_access_token("token")
        client.metadata['tokens'] = new_tokens

# Client instances are independent from first and second.
await asyncio.gather(first(), second())
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • enable_debugging (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information. Like the response status, route, taken time and so on.
  • "TRACE" | TRACE: This will log the response headers along with the minimal information.
RESTPool( token: str, /, *, client_secret: Optional[str] = None, client_id: Optional[int] = None, client_session: Optional[aiohttp.client.ClientSession] = None, max_retries: int = 4, enable_debugging: Union[Literal['TRACE'], bool, int] = False)
266    def __init__(
267        self,
268        token: str,
269        /,
270        *,
271        client_secret: typing.Optional[str] = None,
272        client_id: typing.Optional[int] = None,
273        client_session: typing.Optional[aiohttp.ClientSession] = None,
274        max_retries: int = 4,
275        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
276    ) -> None:
277        self._client_secret = client_secret
278        self._client_id = client_id
279        self._token: str = token
280        self._max_retries = max_retries
281        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
282        self._enable_debug = enable_debugging
283        self._client_session = client_session
client_id: Optional[int]
metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

Pool's Metadata. This is different from client instance metadata.

@typing.final
def acquire(self) -> RESTClient:
294    @typing.final
295    def acquire(self) -> RESTClient:
296        """Acquires a new `RESTClient` instance from this REST pool.
297
298        Returns
299        -------
300        `RESTClient`
301            An instance of a REST client.
302        """
303        return RESTClient(
304            self._token,
305            client_secret=self._client_secret,
306            client_id=self._client_id,
307            max_retries=self._max_retries,
308            enable_debugging=self._enable_debug,
309            client_session=self._client_session,
310        )

Acquires a new RESTClient instance from this REST pool.

Returns
@typing.final
class Race(builtins.int, aiobungie.Enum):
495@typing.final
496class Race(int, Enum):
497    """An Enum for Destiny races."""
498
499    HUMAN = 0
500    AWOKEN = 1
501    EXO = 2
502    UNKNOWN = 3

An Enum for Destiny races.

HUMAN = <Race.HUMAN: 0>
AWOKEN = <Race.AWOKEN: 1>
EXO = <Race.EXO: 2>
UNKNOWN = <Race.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Raid(builtins.int, aiobungie.Enum):
143@typing.final
144class Raid(int, Enum):
145    """An Enum for all available raids in Destiny 2."""
146
147    DSC = 910380154
148    """Deep Stone Crypt"""
149
150    LW = 2122313384
151    """Last Wish"""
152
153    VOG = 3881495763
154    """Normal Valut of Glass"""
155
156    GOS = 3458480158
157    """Garden Of Salvation"""

An Enum for all available raids in Destiny 2.

DSC = <Raid.DSC: 910380154>

Deep Stone Crypt

LW = <Raid.LW: 2122313384>

Last Wish

VOG = <Raid.VOG: 3881495763>

Normal Valut of Glass

GOS = <Raid.GOS: 3458480158>

Garden Of Salvation

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class RateLimitedError(aiobungie.HTTPError):
253@attrs.define(auto_exc=True)
254class RateLimitedError(HTTPError):
255    """Raised when too many request status code is returned."""
256
257    http_status: http.HTTPStatus = attrs.field(
258        default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False
259    )
260    """The request response http status."""
261
262    url: typedefs.StrOrURL
263    """The URL/endpoint caused this error."""
264
265    body: typing.Any
266    """The response body."""
267
268    retry_after: float = attrs.field(default=0.0)
269    """The amount of seconds you need to wait before retrying to requests."""
270
271    message: str = attrs.field(init=False)
272    """A Bungie human readable message describes the cause of the error."""
273
274    @message.default  # type: ignore
275    def _(self) -> str:
276        return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!"
277
278    def __str__(self) -> str:
279        return self.message

Raised when too many request status code is returned.

RateLimitedError(url: Union[str, yarl.URL], body: Any, retry_after: float = 0.0)
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default):
3    self.http_status = attr_dict['http_status'].default
4    self.url = url
5    self.body = body
6    self.retry_after = retry_after
7    self.message = __attr_factory_message(self)
8    BaseException.__init__(self, self.url,self.body,self.retry_after)

Method generated by attrs for class RateLimitedError.

http_status: http.HTTPStatus

The request response http status.

url: Union[str, yarl.URL]

The URL/endpoint caused this error.

body: Any

The response body.

retry_after: float

The amount of seconds you need to wait before retrying to requests.

message: str

A Bungie human readable message describes the cause of the error.

Inherited Members
builtins.BaseException
with_traceback
args
@typing.final
class RecordState(aiobungie.Flag):
48@typing.final
49class RecordState(enums.Flag):
50    """An enum for records component states."""
51
52    NONE = 0
53    REDEEMED = 1 << 0
54    UNAVAILABLE = 1 << 1
55    OBJECTIVE_NOT_COMPLETED = 1 << 2
56    OBSCURED = 1 << 3
57    INVISIBLE = 1 << 4
58    ENTITLEMENT_UNOWNED = 1 << 5
59    CAN_EQUIP_TITLE = 1 << 6

An enum for records component states.

NONE = <RecordState.NONE: 0>
REDEEMED = <RecordState.REDEEMED: 1>
UNAVAILABLE = <RecordState.UNAVAILABLE: 2>
OBJECTIVE_NOT_COMPLETED = <RecordState.OBJECTIVE_NOT_COMPLETED: 4>
OBSCURED = <RecordState.OBSCURED: 8>
INVISIBLE = <RecordState.INVISIBLE: 16>
ENTITLEMENT_UNOWNED = <RecordState.ENTITLEMENT_UNOWNED: 32>
CAN_EQUIP_TITLE = <RecordState.CAN_EQUIP_TITLE: 64>
Inherited Members
Flag
name
value
@typing.final
class Relationship(builtins.int, aiobungie.Enum):
690@typing.final
691class Relationship(int, Enum):
692    """An enum for bungie friends relationship types."""
693
694    UNKNOWN = 0
695    FRIEND = 1
696    INCOMING_REQUEST = 2
697    OUTGOING_REQUEST = 3

An enum for bungie friends relationship types.

UNKNOWN = <Relationship.UNKNOWN: 0>
FRIEND = <Relationship.FRIEND: 1>
INCOMING_REQUEST = <Relationship.INCOMING_REQUEST: 2>
OUTGOING_REQUEST = <Relationship.OUTGOING_REQUEST: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class RequestMethod(builtins.str, aiobungie.Enum):
181class RequestMethod(str, enums.Enum):
182    """HTTP request methods enum."""
183
184    GET = "GET"
185    """GET methods."""
186    POST = "POST"
187    """POST methods."""
188    PUT = "PUT"
189    """PUT methods."""
190    PATCH = "PATCH"
191    """PATCH methods."""
192    DELETE = "DELETE"
193    """DELETE methods"""

HTTP request methods enum.

GET = <RequestMethod.GET: GET>

GET methods.

POST = <RequestMethod.POST: POST>

POST methods.

PUT = <RequestMethod.PUT: PUT>

PUT methods.

PATCH = <RequestMethod.PATCH: PATCH>

PATCH methods.

DELETE = <RequestMethod.DELETE: DELETE>

DELETE methods

Inherited Members
Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
@attrs.define(auto_exc=True)
class ResponseError(aiobungie.HTTPException):
248@attrs.define(auto_exc=True)
249class ResponseError(HTTPException):
250    """Exception for other HTTP response errors."""

Exception for other HTTP response errors.

ResponseError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class ResponseError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class Stat(builtins.int, aiobungie.Enum):
517@typing.final
518class Stat(int, Enum):
519    """An Enum for Destiny 2 character stats."""
520
521    NONE = 0
522    MOBILITY = 2996146975
523    RESILIENCE = 392767087
524    RECOVERY = 1943323491
525    DISCIPLINE = 1735777505
526    INTELLECT = 144602215
527    STRENGTH = 4244567218
528    LIGHT_POWER = 1935470627

An Enum for Destiny 2 character stats.

NONE = <Stat.NONE: 0>
MOBILITY = <Stat.MOBILITY: 2996146975>
RESILIENCE = <Stat.RESILIENCE: 392767087>
RECOVERY = <Stat.RECOVERY: 1943323491>
DISCIPLINE = <Stat.DISCIPLINE: 1735777505>
INTELLECT = <Stat.INTELLECT: 144602215>
STRENGTH = <Stat.STRENGTH: 4244567218>
LIGHT_POWER = <Stat.LIGHT_POWER: 1935470627>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
TRACE = 5
@typing.final
class TierType(builtins.int, aiobungie.Enum):
632@typing.final
633class TierType(int, Enum):
634    """An enum for a Destiny 2 item tier type."""
635
636    UNKNOWN = 0
637    CURRENCY = 1
638    BASIC = 2
639    COMMON = 3
640    RARE = 4
641    SUPERIOR = 5
642    EXOTIC = 6

An enum for a Destiny 2 item tier type.

UNKNOWN = <TierType.UNKNOWN: 0>
CURRENCY = <TierType.CURRENCY: 1>
BASIC = <TierType.BASIC: 2>
COMMON = <TierType.COMMON: 3>
RARE = <TierType.RARE: 4>
SUPERIOR = <TierType.SUPERIOR: 5>
EXOTIC = <TierType.EXOTIC: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class TransferStatus(aiobungie.Flag):
742@typing.final
743class TransferStatus(Flag):
744    """An enum for items transfer statuses."""
745
746    CAN_TRANSFER = 0
747    """The item can be transferred."""
748    IS_EQUIPPED = 1 << 0
749    """You can't transfer since the item is equipped."""
750    NOT_TRASNFERRABLE = 1 << 1
751    """This item can not be transferred."""
752    COULD_BE_TRANSFERRED = 1 << 2
753    """You can transfer the item. But the place you're trying to put it at has no space for it."""

An enum for items transfer statuses.

CAN_TRANSFER = <TransferStatus.CAN_TRANSFER: 0>

The item can be transferred.

IS_EQUIPPED = <TransferStatus.IS_EQUIPPED: 1>

You can't transfer since the item is equipped.

NOT_TRASNFERRABLE = <TransferStatus.NOT_TRASNFERRABLE: 2>

This item can not be transferred.

COULD_BE_TRANSFERRED = <TransferStatus.COULD_BE_TRANSFERRED: 4>

You can transfer the item. But the place you're trying to put it at has no space for it.

Inherited Members
Flag
name
value
UNDEFINED = UNDEFINED
@attrs.define(auto_exc=True)
class Unauthorized(aiobungie.HTTPException):
155@attrs.define(auto_exc=True)
156class Unauthorized(HTTPException):
157    """An exception that's raised when trying to make unauthorized call to a resource and it returns 404."""
158
159    http_status: http.HTTPStatus = attrs.field(
160        default=http.HTTPStatus.UNAUTHORIZED, init=False
161    )

An exception that's raised when trying to make unauthorized call to a resource and it returns 404.

Unauthorized( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Unauthorized.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
UndefinedOr = typing.Union[UndefinedType, +_T]
class UndefinedType:
33class UndefinedType:
34    """An `UNDEFINED` type."""
35
36    __instance: typing.Optional[UndefinedType] = None
37
38    def __bool__(self) -> typing.Literal[False]:
39        return False
40
41    def __int__(self) -> typing.Literal[0]:
42        return 0
43
44    def __repr__(self) -> str:
45        return "UNDEFINED"
46
47    def __str__(self) -> str:
48        return "UNDEFINED"
49
50    def __new__(cls) -> UndefinedType:
51        if cls.__instance is None:
52            o = super().__new__(cls)
53            cls.__instance = o
54        return cls.__instance

An UNDEFINED type.

@typing.final
class ValueUIStyle(builtins.int, aiobungie.Enum):
75@typing.final
76class ValueUIStyle(int, enums.Enum):
77    AUTOMATIC = 0
78    FRACTION = 1
79    CHECK_BOX = 2
80    PERCENTAGE = 3
81    DATETIME = 4
82    FRACTION_FLOAT = 5
83    INTEGER = 6
84    TIME_DURATION = 7
85    HIDDEN = 8
86    MULTIPLIER = 9
87    GREEN_PIPS = 10
88    RED_PIPS = 11
89    EXPLICIT_PERCENTAGE = 12
90    RAW_FLOAT = 13
91    LEVEL_AND_REWARD = 14

An enumeration.

AUTOMATIC = <ValueUIStyle.AUTOMATIC: 0>
FRACTION = <ValueUIStyle.FRACTION: 1>
CHECK_BOX = <ValueUIStyle.CHECK_BOX: 2>
PERCENTAGE = <ValueUIStyle.PERCENTAGE: 3>
DATETIME = <ValueUIStyle.DATETIME: 4>
FRACTION_FLOAT = <ValueUIStyle.FRACTION_FLOAT: 5>
INTEGER = <ValueUIStyle.INTEGER: 6>
TIME_DURATION = <ValueUIStyle.TIME_DURATION: 7>
HIDDEN = <ValueUIStyle.HIDDEN: 8>
MULTIPLIER = <ValueUIStyle.MULTIPLIER: 9>
GREEN_PIPS = <ValueUIStyle.GREEN_PIPS: 10>
RED_PIPS = <ValueUIStyle.RED_PIPS: 11>
EXPLICIT_PERCENTAGE = <ValueUIStyle.EXPLICIT_PERCENTAGE: 12>
RAW_FLOAT = <ValueUIStyle.RAW_FLOAT: 13>
LEVEL_AND_REWARD = <ValueUIStyle.LEVEL_AND_REWARD: 14>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Vendor(builtins.int, aiobungie.Enum):
240@typing.final
241class Vendor(int, Enum):
242    """An Enum for all available vendors in Destiny 2."""
243
244    ZAVALA = 69482069
245    XUR = 2190858386
246    BANSHE = 672118013
247    SPIDER = 863940356
248    SHAXX = 3603221665
249    KADI = 529635856
250    """Postmaster exo."""
251    YUNA = 1796504621
252    """Asia servers only."""
253    EVERVERSE = 3361454721
254    AMANDA = 460529231
255    """Amanda holiday"""
256    CROW = 3611983588
257    HAWTHORNE = 3347378076
258    ADA1 = 350061650
259    DRIFTER = 248695599
260    IKORA = 1976548992
261    SAINT = 765357505
262    """Saint-14"""
263    ERIS_MORN = 1616085565
264    SHAW_HAWN = 1816541247
265    """COSMODROME Guy"""
266    VARIKS = 2531198101

An Enum for all available vendors in Destiny 2.

ZAVALA = <Vendor.ZAVALA: 69482069>
XUR = <Vendor.XUR: 2190858386>
BANSHE = <Vendor.BANSHE: 672118013>
SPIDER = <Vendor.SPIDER: 863940356>
SHAXX = <Vendor.SHAXX: 3603221665>
KADI = <Vendor.KADI: 529635856>

Postmaster exo.

YUNA = <Vendor.YUNA: 1796504621>

Asia servers only.

EVERVERSE = <Vendor.EVERVERSE: 3361454721>
AMANDA = <Vendor.AMANDA: 460529231>

Amanda holiday

CROW = <Vendor.CROW: 3611983588>
HAWTHORNE = <Vendor.HAWTHORNE: 3347378076>
ADA1 = <Vendor.ADA1: 350061650>
DRIFTER = <Vendor.DRIFTER: 248695599>
IKORA = <Vendor.IKORA: 1976548992>
SAINT = <Vendor.SAINT: 765357505>

Saint-14

ERIS_MORN = <Vendor.ERIS_MORN: 1616085565>
SHAW_HAWN = <Vendor.SHAW_HAWN: 1816541247>

COSMODROME Guy

VARIKS = <Vendor.VARIKS: 2531198101>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class WeaponType(builtins.int, aiobungie.Enum):
531@typing.final
532class WeaponType(int, Enum):
533    """Enums for The three Destiny Weapon Types"""
534
535    NONE = 0
536    KINETIC = 1498876634
537    ENERGY = 2465295065
538    POWER = 953998645

Enums for The three Destiny Weapon Types

NONE = <WeaponType.NONE: 0>
KINETIC = <WeaponType.KINETIC: 1498876634>
ENERGY = <WeaponType.ENERGY: 2465295065>
POWER = <WeaponType.POWER: 953998645>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
annotations = _Feature((3, 7, 0, 'beta', 1), (3, 11, 0, 'alpha', 0), 16777216)
def into_iter( iterable: collections.abc.Iterable[~Item]) -> Iterator[~Item]:
559def into_iter(
560    iterable: collections.Iterable[Item],
561) -> Iterator[Item]:
562    """Transform an iterable into an flat iterator.
563
564    Example
565    -------
566    ```py
567    sequence = [1,2,3]
568    for item in aiobungie.into_iter(sequence).reversed():
569        print(item)
570    # 3
571    # 2
572    # 1
573    ```
574
575    Parameters
576    ----------
577    iterable: `typing.Iterable[Item]`
578        The iterable to convert.
579
580    Raises
581    ------
582    `StopIteration`
583        If no elements are left in the iterator.
584    """
585    return Iterator(iterable)

Transform an iterable into an flat iterator.

Example
sequence = [1,2,3]
for item in aiobungie.into_iter(sequence).reversed():
    print(item)
# 3
# 2
# 1
Parameters
  • iterable (typing.Iterable[Item]): The iterable to convert.
Raises
  • StopIteration: If no elements are left in the iterator.
async def raise_error( response: aiohttp.client_reqrep.ClientResponse) -> AiobungieError:
282async def raise_error(response: aiohttp.ClientResponse) -> AiobungieError:
283    """Generates and raise exceptions on error responses."""
284
285    # Not a JSON response, raise immediately.
286
287    # Also Bungie sometimes get funky and return HTML instead of JSON when making an authorized
288    # request with a dummy access token. I can't really do anything about this..
289    if response.content_type != "application/json":
290        return HTTPError(
291            f"Expected JSON content but got {response.content_type!s}, {response.real_url!s}",
292            http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE,
293        )
294
295    body = await response.json()
296    message: str = body.get("Message", "UNDEFINED_MESSAGE")
297    error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS")
298    message_data: dict[str, str] = body.get("MessageData", {})
299    throttle_seconds: int = body.get("ThrottleSeconds", 0)
300    error_code: int = body.get("ErrorCode", 0)
301
302    # Standard HTTP status.
303    if response.status == http.HTTPStatus.NOT_FOUND:
304        return NotFound(
305            message=message,
306            error_code=error_code,
307            throttle_seconds=throttle_seconds,
308            url=str(response.real_url),
309            body=body,
310            headers=response.headers,
311            error_status=error_status,
312            message_data=message_data,
313        )
314
315    elif response.status == http.HTTPStatus.FORBIDDEN:
316        return Forbidden(
317            message=message,
318            error_code=error_code,
319            throttle_seconds=throttle_seconds,
320            url=str(response.real_url),
321            body=body,
322            headers=response.headers,
323            error_status=error_status,
324            message_data=message_data,
325        )
326
327    elif response.status == http.HTTPStatus.UNAUTHORIZED:
328        return Unauthorized(
329            message=message,
330            error_code=error_code,
331            throttle_seconds=throttle_seconds,
332            url=str(response.real_url),
333            body=body,
334            headers=response.headers,
335            error_status=error_status,
336            message_data=message_data,
337        )
338
339    elif response.status == http.HTTPStatus.BAD_REQUEST:
340        # Membership needs to be alone.
341        if error_status == "InvalidParameters":
342            return MembershipTypeError(
343                message=message,
344                body=body,
345                headers=response.headers,
346                url=str(response.url),
347                membership_type=message_data["membershipType"],
348                required_membership=message_data["membershipInfo.membershipType"],
349                membership_id=int(message_data["membershipId"]),
350            )
351        return BadRequest(
352            message=message,
353            body=body,
354            headers=response.headers,
355            url=str(response.url),
356        )
357
358    status = http.HTTPStatus(response.status)
359
360    if 400 <= status < 500:
361        return ResponseError(
362            message=message,
363            error_code=error_code,
364            throttle_seconds=throttle_seconds,
365            url=str(response.real_url),
366            body=body,
367            headers=response.headers,
368            error_status=error_status,
369            message_data=message_data,
370            http_status=status,
371        )
372
373    # Need to self handle ~5xx errors
374    elif 500 <= status < 600:
375        # No API key or method requires OAuth2 most likely.
376        if error_status in {
377            "ApiKeyMissingFromRequest",
378            "WebAuthRequired",
379            "ApiInvalidOrExpiredKey",
380            "AuthenticationInvalid",
381            "AuthorizationCodeInvalid",
382        }:
383            return Unauthorized(
384                message=message,
385                error_code=error_code,
386                throttle_seconds=throttle_seconds,
387                url=str(response.real_url),
388                body=body,
389                headers=response.headers,
390                error_status=error_status,
391                message_data=message_data,
392            )
393
394        # Anything contains not found.
395        elif (
396            "NotFound" in error_status or error_status == "UserCannotFindRequestedUser"
397        ):
398            return NotFound(
399                message=message,
400                error_code=error_code,
401                throttle_seconds=throttle_seconds,
402                url=str(response.real_url),
403                body=body,
404                headers=response.headers,
405                error_status=error_status,
406                message_data=message_data,
407            )
408
409        # Other 5xx errors.
410        else:
411            return InternalServerError(
412                message=message,
413                error_code=error_code,
414                throttle_seconds=throttle_seconds,
415                url=str(response.real_url),
416                body=body,
417                headers=response.headers,
418                error_status=error_status,
419                message_data=message_data,
420                http_status=status,
421            )
422    # Something else.
423    else:
424        return HTTPException(
425            message=message,
426            error_code=error_code,
427            throttle_seconds=throttle_seconds,
428            url=str(response.real_url),
429            body=body,
430            headers=response.headers,
431            error_status=error_status,
432            message_data=message_data,
433            http_status=status,
434        )

Generates and raise exceptions on error responses.

def stringify_http_message(headers: 'collections.Mapping[str, str]') -> str:
437def stringify_http_message(headers: collections.Mapping[str, str]) -> str:
438    return (
439        "{ \n"
440        + "\n".join(  # noqa: W503
441            f"{f'   {key}'}: {value}"
442            if key not in ("Authorization", "X-API-KEY")
443            else f"   {key}: HIDDEN_TOKEN"
444            for key, value in headers.items()
445        )
446        + "\n}"  # noqa: W503
447    )